diff --git a/PremiumSpawner_Tutorial.txt b/PremiumSpawner_Tutorial.txt new file mode 100644 index 0000000..92cb67d --- /dev/null +++ b/PremiumSpawner_Tutorial.txt @@ -0,0 +1,621 @@ + +----------------------------------+ + | PREMIUM SPAWNER - Basic Tutorial | + +----------------------------------+ + + ------------------------------- + English last update: Feb/2014 + ------------------------------- + + 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 "map" 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 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 + 8. PART VII - Spawns' Overseer + + +>>>>>>>>>>>>>>>>>>>>>>>>>>> +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 open READ-ME FIRST.txt and follow its instructions. + + +>>>>>>>>>>>>>>>>>> +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: + Let there be light (Create world) -- [createworld + Apocalypse now (Clear all facets) -- [clearall +SELECT SPAWNS BY EXPANSION: + UO Classic Spawns (pre-T2A) -------- [spawngen uoclassic/UOClassic.map + UO Mondain's Legacy Spawns --------- [SpawnUOML + UO KR, SA and HS Spawns ------------ [SpawnCurrent +REMOVE SPAWNS BY EXPANSION: + UO Classic Spawns (pre-T2A) -------- [spawngen unload 1000 + UO Mondain's Legacy Spawns --------- [UnloadUOML + UO KR, SA and HS Spawns ------------ [UnloadCurrent +SMART PLAYER RANGE SENSITIVE: + Generate Spawns' Overseer ---------- [GenSeers + Remove Spawns' Overseer ------------ [RemSeers +SAVE SPAWNERS: + All spawns (spawns.map) ------------ [spawngen save + 'By Hand' spawns (byhand.map) ------ [spawngen savebyhand + Spawns inside region (region.map) -- [spawngen save RegionName + Spawns inside coordinates ---------- [spawngen save x1 y1 x2 y2 +REMOVE SPAWNERS: + All spawner in ALL facets ---------- [spawngen remove + All spawners in THIS facet --------- [spawngen cleanfacet + Remove spawners by SpawnID --------- [spawngen unload SpawnID + Remove inside Coordinates ---------- [spawngen remove x1 y1 x2 y2 + Remove spawners inside Region ------ [spawngen remove RegionName +EDITOR: + Spawn Editor ----------------------- [editor +CONVERSION UTILITY: + RunUO Spawners to Premium ---------- [rse +CUSTOM REGIONS IN A BOX: + Add a Region Controller ------------ [Add RegionControl + + + 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. + + But you could write otherwise, time in seconds, minutes or hours: + |10s| = ten seconds; + |10m| (or just |10|, the default) = ten minutes; + |10h| = ten hours. + +- 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. + + +>>>>>>>>>>>>>>>>>>>>>>>>>>> +PART VII - SPAWNS' OVERSEER +<<<<<<<<<<<<<<<<<<<<<<<<<<< + +Revision 22 has added Spawners' Overseer engine, the new incarnation of +Smart Player Range Sensitive. + +How it works: +It has a range, that can be set by a GM or higher. It checks players in +range every time the clock time ticks. If there is a player in range (or +a non-hidden Staff Member) it will check players again only after 30 min +(this time can be changed). If there is no players in range (or if Staff +Members are hidden, but in range) it will disable all PremiumSpawners in +range, deleting mobiles and items in range, and it will check for +players every 5 seconds. + +[GenSeers - generates Overseers crystal by reading configuration files + at Data\Monsters\Overseers. + +There is no OverSeers configuration files yet. So it generates no +OverSeers. The engine is done, it is working, but you need a config file +to tells the engine where to place OverSeers. + +[RemSeers - removes all Overseers. + + +>>>>>> ADDING >>>>>> + +One option it to add OverSeers yourself, by hand. + +[add SpawnsOverseer +- this will add an OverSeer with range 20 (square of 40 x 40). + +[add SpawnsOverseer 50 +- this will add an OverSeer with range 50 (square of 100 x 100). + + +>>>>>> CONFIG FILES >>>>>> + +And look at: + +...\Data\Nerun's Distro\Spawns\overseers\trammel\Overseers.cfg + +It is an example of OverSeer config file: + +SpawnsOverseer 7966 +5433 1102 0 + +It is simple: bellow "SpawnsOverseer 7966" write coordinates (x,y,z) where +you want to put them. + + +>>>>>> RANGES >>>>>> + +I thin you can write different ranges too, something like this: + +SpawnsOverseer 7966 (Range=50) +5433 1102 0 + +Remember that default range is 20 if none specified. + +Range is the seer's "watching range". PremiumSpawners inside it range will +be watched by that seer. There is no limit to the range. + +You can place many seers with different ranges: + +SpawnsOverseer 7966 +5433 1102 0 +1234 970 0 +3456 456 0 + +SpawnsOverseer 7966 (Range=50) +5433 1102 0 + +You can change other parameters: + + SpawnsOverseer 7966 (InRangeDelay=30; OutRangeDelay=5) + 5433 1102 0 + +And use all the together: + + SpawnsOverseer 7966 (Range=50; InRangeDelay=30; OutRangeDelay=5) + 5433 1102 0 + +InRangeDelay = time in minutes to next check if players are in range + +OutRangeDelay = time in seconds to next check if there is no players in range + +>>>>>> ITEMID >>>>>> + +Always use "SpawnsOverseer 7966", the number is the ItemID of +SpawnsOverseer item. + +>>>>>> COMMENTS >>>>>> + +Use # to add comments that will not be read by [GenSeers: + +# This is a comment line +SpawnsOverseer 7966 (Range=50) +5433 1102 0 + +>>>>>> FOLDERS >>>>>> + +Place the CFG file in the right folder. + +Trammel: +...\Data\Nerun's Distro\Spawns\overseers\trammel\Overseers.cfg + +Felucca: +...\Data\Nerun's Distro\Spawns\overseers\felucca\Overseers.cfg + +etc + +>>>>>> .CFG FILE NAME >>>>>> + +You can place more then one cfg inside the same folder, and don't +need to have the name Overseers.cfg. Files can have any name. You +can do a file "Graveyards.cfg" for all graveyards in a facet. Plus +another called "Florests.cfg" for florests and open areas etc. diff --git a/Scripts/Commands/BandSelf.cs b/Scripts/Commands/BandSelf.cs new file mode 100644 index 0000000..f05b447 --- /dev/null +++ b/Scripts/Commands/BandSelf.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; +using Server.Commands; +using Server.Mobiles; + +namespace Server.Commands +{ + public class BandSelf + { + public static void Initialize() + { + CommandSystem.Register("Bandself", AccessLevel.Player, new CommandEventHandler(Bandself_OnCommand)); + } + + [Usage("Bandself")] + [Description("Uses a bandage from the player's backpack on themselves.")] + public static void Bandself_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (BandageContext.GetContext(from) != null) + { + from.SendMessage( 33, "You are already applying a bandage." ); + return; + } + Bandage bandage = from.Backpack.FindItemByType(); + + if (bandage != null) + { + if (BandageContext.BeginHeal(from, from) != null) + { + bandage.Consume(); + } + } + else + { + from.SendMessage("You do not have any bandages in your backpack."); + } + } + } +} diff --git a/Scripts/Commands/ClearAll.cs b/Scripts/Commands/ClearAll.cs new file mode 100644 index 0000000..03f2cc7 --- /dev/null +++ b/Scripts/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/Commands/MoveToLocation.cs b/Scripts/Commands/MoveToLocation.cs new file mode 100644 index 0000000..1ce72aa --- /dev/null +++ b/Scripts/Commands/MoveToLocation.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Commands; + +namespace Server.Commands +{ + public class MoveToLocCommand + { + public static void Initialize() + { + // Registers the command. GMs and Admins can use it. + CommandSystem.Register( "MoveToLoc", AccessLevel.GameMaster, new CommandEventHandler( MoveToLoc_OnCommand ) ); + } + + [Usage( "MoveToLoc [+x/-x] [+y/-y] [+z/-z]" )] + public static void MoveToLoc_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + if ( e.Length < 2 ) + { + from.SendMessage( "Usage: [MoveToLoc [+x/-x] [+y/-y] [+z/-z]" ); + return; + } + + int currentX = from.X; + int currentY = from.Y; + int currentZ = from.Z; + + int targetX = ParseCoordinate( e.GetString( 0 ), currentX ); + int targetY = ParseCoordinate( e.GetString( 1 ), currentY ); + int targetZ = ( e.Length >= 3 ) ? ParseCoordinate( e.GetString( 2 ), currentZ ) : currentZ; + + from.MoveToWorld( new Point3D( targetX, targetY, targetZ ), from.Map ); + } + + private static int ParseCoordinate( string input, int currentVal ) + { + if ( string.IsNullOrEmpty( input ) ) + return currentVal; + + // Check if it starts with a relative modification operator + if ( input.StartsWith( "+" ) || input.StartsWith( "-" ) ) + { + int modifier = Utility.ToInt32( input ); + return currentVal + modifier; + } + + // Otherwise treat it as a standard absolute coordinate + return Utility.ToInt32( input ); + } + } +} diff --git a/Scripts/Gumps/AddDoorGump.cs b/Scripts/Gumps/AddDoorGump.cs index c76fdfa..93fb415 100644 --- a/Scripts/Gumps/AddDoorGump.cs +++ b/Scripts/Gumps/AddDoorGump.cs @@ -50,7 +50,7 @@ namespace Server.Gumps } else { - AddBlueBack( 265, 145 ); + AddBlueBack( 1010, 145 ); for ( int i = 0; i < m_Types.Length; ++i ) { @@ -104,10 +104,24 @@ namespace Server.Gumps public static DoorInfo[] m_Types = new DoorInfo[] { new DoorInfo( typeof( MetalDoor ), 0x675 ), + new DoorInfo( typeof( MetalDoor2), 0x6C5 ), new DoorInfo( typeof( RattanDoor ), 0x695 ), new DoorInfo( typeof( DarkWoodDoor ), 0x6A5 ), new DoorInfo( typeof( LightWoodDoor ), 0x6D5 ), - new DoorInfo( typeof( StrongWoodDoor ), 0x6E5 ) + new DoorInfo( typeof( StrongWoodDoor ), 0x6E5 ), + new DoorInfo( typeof( LightWoodGate ), 0x839 ), + new DoorInfo( typeof( DarkWoodGate ), 0x866 ), + new DoorInfo( typeof( MediumWoodDoor ), 0x6B5 ), + new DoorInfo( typeof( SecretLightWoodDoor ), 0x344 ), + new DoorInfo( typeof( SecretWoodenDoor ), 0x334 ), + new DoorInfo( typeof( SecretDungeonDoor), 0x314 ), + new DoorInfo( typeof( SecretStoneDoor1 ), 0xE8 ), + new DoorInfo( typeof( SecretStoneDoor2 ), 0x324 ), + new DoorInfo( typeof( SecretStoneDoor3 ), 0x354 ), + new DoorInfo( typeof( IronGateShort ), 0x84C ), + new DoorInfo( typeof( IronGate ), 0x824 ), + new DoorInfo( typeof( BarredMetalDoor ), 0x685 ), + new DoorInfo( typeof( BarredMetalDoor2 ), 0x1FED ), }; } @@ -122,4 +136,4 @@ namespace Server.Gumps m_BaseID = baseID; } } -} \ No newline at end of file +} diff --git a/Scripts/Items/Resources/Tailor/Cotton.cs b/Scripts/Items/Resources/Tailor/Cotton.cs index a167d4e..319368d 100644 --- a/Scripts/Items/Resources/Tailor/Cotton.cs +++ b/Scripts/Items/Resources/Tailor/Cotton.cs @@ -77,7 +77,7 @@ namespace Server.Items m_Cotton = cotton; } - protected override void OnTarget( Mobile from, object targeted ) + protected override void OnTarget( Mobile from, object targeted ) { if ( m_Cotton.Deleted ) return; @@ -101,8 +101,28 @@ namespace Server.Items } else { - m_Cotton.Consume(); - wheel.BeginSpin( new SpinCallback( Cotton.OnSpun ), from, m_Cotton.Hue ); + int amount = m_Cotton.Amount; + int hue = m_Cotton.Hue; + + m_Cotton.Delete(); + + wheel.BeginSpin( ( w, m, h ) => + { + int totalThread = 6 * amount; + + while ( totalThread > 0 ) + { + int threadToGive = Math.Min( totalThread, 60000 ); + + Item spools = new SpoolOfThread( threadToGive ); + spools.Hue = h; + m.AddToBackpack( spools ); + + totalThread -= threadToGive; + } + + m.SendLocalizedMessage( 1010577 ); // You put the spools of thread in your backpack. + }, from, hue ); } } else @@ -112,4 +132,4 @@ namespace Server.Items } } } -} \ No newline at end of file +} diff --git a/Scripts/Items/Resources/Tailor/Flax.cs b/Scripts/Items/Resources/Tailor/Flax.cs index e4ce574..6de1eae 100644 --- a/Scripts/Items/Resources/Tailor/Flax.cs +++ b/Scripts/Items/Resources/Tailor/Flax.cs @@ -66,8 +66,7 @@ namespace Server.Items { m_Flax = flax; } - - protected override void OnTarget( Mobile from, object targeted ) + protected override void OnTarget( Mobile from, object targeted ) { if ( m_Flax.Deleted ) return; @@ -91,8 +90,28 @@ namespace Server.Items } else { - m_Flax.Consume(); - wheel.BeginSpin( new SpinCallback( Flax.OnSpun ), from, m_Flax.Hue ); + int amount = m_Flax.Amount; + int hue = m_Flax.Hue; + + m_Flax.Delete(); + + wheel.BeginSpin( ( w, m, h ) => + { + int totalThread = 6 * amount; + + while ( totalThread > 0 ) + { + int threadToGive = Math.Min( totalThread, 60000 ); + + Item spools = new SpoolOfThread( threadToGive ); + spools.Hue = h; + m.AddToBackpack( spools ); + + totalThread -= threadToGive; + } + + m.SendLocalizedMessage( 1010577 ); // You put the spools of thread in your backpack. + }, from, hue ); } } else @@ -102,4 +121,4 @@ namespace Server.Items } } } -} \ No newline at end of file +} diff --git a/Scripts/Items/Resources/Tailor/Wool.cs b/Scripts/Items/Resources/Tailor/Wool.cs index 3286d6c..b8aaca4 100644 --- a/Scripts/Items/Resources/Tailor/Wool.cs +++ b/Scripts/Items/Resources/Tailor/Wool.cs @@ -77,7 +77,7 @@ namespace Server.Items m_Wool = wool; } - protected override void OnTarget( Mobile from, object targeted ) + protected override void OnTarget( Mobile from, object targeted ) { if ( m_Wool.Deleted ) return; @@ -101,9 +101,34 @@ namespace Server.Items } 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 ); + // 1. Capture the total stack amount and its hue + int amount = m_Wool.Amount; + int hue = m_Wool.Hue; + + // 2. Destroy the entire pile of wool at once + m_Wool.Delete(); + + // 3. Start the spin cycle and use a lambda for the multiplied yield + wheel.BeginSpin( ( w, m, h ) => + { + // 1 wool = 3 balls of yarn. Calculate total yield. + int totalYarn = 3 * amount; + + // 4. Safely loop the creation to prevent going over the 60,000 item limit + while ( totalYarn > 0 ) + { + int yarnToGive = Math.Min( totalYarn, 60000 ); + + // In RunUO, "DarkYarn" is the core class used for all balls of yarn + Item yarn = new DarkYarn( yarnToGive ); + yarn.Hue = h; + m.AddToBackpack( yarn ); + + totalYarn -= yarnToGive; + } + + m.SendLocalizedMessage( 1010576 ); // You put the balls of yarn in your backpack. + }, from, hue ); } } else @@ -155,4 +180,4 @@ namespace Server.Items 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 index e27e6f2..8fa22fc 100644 --- a/Scripts/Items/Resources/Tailor/YarnsAndThreads.cs +++ b/Scripts/Items/Resources/Tailor/YarnsAndThreads.cs @@ -13,7 +13,7 @@ namespace Server.Items public BaseClothMaterial( int itemID, int amount ) : base( itemID ) { Stackable = true; - Weight = 1.0; + Weight = 0.25; Amount = amount; } @@ -67,7 +67,7 @@ namespace Server.Items m_Material = material; } - protected override void OnTarget( Mobile from, object targeted ) + protected override void OnTarget( Mobile from, object targeted ) { if ( m_Material.Deleted ) return; @@ -83,22 +83,43 @@ namespace Server.Items { from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. } - else if ( loom.Phase < 4 ) + else { - 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 ); + int currentPhase = loom.Phase; + + int neededToFinish = 5 - currentPhase; + + if ( m_Material.Amount >= neededToFinish ) + { + m_Material.Consume( neededToFinish ); + + Item bolt1 = new BoltOfCloth(); + bolt1.Hue = m_Material.Hue; + from.AddToBackpack( bolt1 ); + + loom.Phase = 0; // Reset loom to empty + + int remainingThread = m_Material.Amount; + int extraBolts = remainingThread / 5; + + if ( extraBolts > 0 ) + { + m_Material.Consume( extraBolts * 5 ); + + Item extraBolt = new BoltOfCloth(); + extraBolt.Hue = m_Material.Hue; + extraBolt.Amount = extraBolts; // Stack them if possible + from.AddToBackpack( extraBolt ); + } + + from.SendLocalizedMessage( 500368 ); // You create some cloth and put it in your backpack. + } + else + { + m_Material.Consume(); + ((Item)targeted).SendLocalizedMessageTo( from, 1010001 + currentPhase ); + loom.Phase++; + } } } else @@ -232,4 +253,4 @@ namespace Server.Items int version = reader.ReadInt(); } } -} \ No newline at end of file +} diff --git a/Scripts/Misc/CrashGuard.cs b/Scripts/Misc/CrashGuard.cs index 504758d..f1cb7fd 100644 --- a/Scripts/Misc/CrashGuard.cs +++ b/Scripts/Misc/CrashGuard.cs @@ -14,7 +14,7 @@ namespace Server.Misc { private static bool Enabled = true; private static bool SaveBackup = true; - private static bool RestartServer = true; + private static bool RestartServer = Settings.S_RestartOnCrash; private static bool GenerateReport = true; public static void Initialize() diff --git a/Scripts/Settings.cs b/Scripts/Settings.cs index a0cbb0b..7f23a20 100644 --- a/Scripts/Settings.cs +++ b/Scripts/Settings.cs @@ -4,6 +4,7 @@ namespace Server { public static string S_ServerName = "Avatars Conquest"; public static int S_Port = 8008; + public static bool S_RestartOnCrash = false; public static double S_ServerSaveMinutes = 5.0; // 5-240 minutes range public static double S_ServerSaveWarningSeconds = 15; public static bool S_SaveOnCharacterLogout = true;