zerodowned

Moderator
credit to Dian for helping me with this

Just to be clear, this has nothing to do with creating a custom map.
But let's say you want to take an existing map that's already in the client files and have two copies of it?

This will tell you how to make a copy of that existing map that doesn't require a player to use custom files.

Open MapDefinitions.cs

C#:
 /* 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.TrammelRules);
            RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules);
            RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules);
            RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules);
            RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);
         

            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( <index>, <mapID>, <fileIndex>, <width>, <height>, <season>, <name>, <rules> );
            *  - <index> : An unreserved unique index for this map
            *  - <mapID> : An identification number used in client communications. For any visible maps, this value must be from 0-5
            *  - <fileIndex> : A file identification number. For any visible maps, this value must be from 0-5
            *  - <width>, <height> : Size of the map (in tiles)
            *  - <season> : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation
            *  - <name> : Reference name for the map, used in props gump, get/set commands, region loading, etc
            *  - <rules> : Rules and restrictions associated with the map. See documentation for details
            */

If you read through the information in there it tells you everything you need to know.

So, if you simply add a line like:

RegisterMap(33, 1, 1, 7168, 4096, 1, "testtram", MapRules.TrammelRules);
after
RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);

You create a map with the index of 33 [first usable index #] using the Trammel map and Trammel rules.
*Tip: Make sure the size of the map you're copying matches the copy.

Start/Restart your shard ( you can just type restart into the console, no need to sign in )
Go to anywhere in Tram, then do the command [set map testtram and target yourself...and there you go

Now, of course it's an ungenerated map, no doors, teleporters, or any of that fun stuff. Those commands/systems won't work due to not supporting a "custom" map
 
This part is going to assume that you are using a copy of a distro map or that you've already set up the regions for a custom one...

After creating a copy, you can go to that map and play on it and everything, but what about setting up region bounds?
I decided to just copy the sections I needed and rename the facet.

Find the file: ServUO\Data\Regions.XML

For each facet you'll see a section starting with <Facet name="Trammel"> and ending that section with </Facet>

So find the facet and region you want to copy and then go to the bottom of page ( you don't have to but it's better to keep track of changes in my opinion ) and paste that just above </ServerRegions>

You should have something like

Code:
<Facet name="CopyofTrammel">
            <region type="DungeonRegion" priority="50" name="Shame">
                    <rect x="5377" y="2" width="257" height="260" />
                    <rect x="5635" y="2" width="260" height="124" />
                    <go x="5395" y="126" z="0" />
                    <entrance x="512" y="1559" />
                    <music name="Dungeon9" />
                </region>
    </Facet>
</ServerRegions>

It would be best if the name matches the Map name you use in MapDefinitions.cs

Now, if you restart the compiler will tell you Map "CopyofTrammel" not found in Server/Map or something.

Looking at ServUO\Server\Map.cs you'll see around line 56

Code:
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]; } }

The numbers in the brackets match the Map index # in MapDefinitions

So assuming in MapDef we added: RegisterMap(33, 1, 1, 7168, 4096, 1, "CopyofTrammel", MapRules.TrammelRules);

Here we'll add: public static Map CopyofTrammel{ get { return m_Maps[33]; } }

Good, okay, now the map is registered and everything. Right? But what about setting up limitations to Recall, Mark, etc?
 
If you want to limit spells like that in Dungeons...

Open the file: ServUO\Scripts\Spells\Base\SpellHelper.cs around line 602 you'll see

Code:
 private static readonly TravelValidator[] m_Validators = new TravelValidator[]
        {
            new TravelValidator(IsFeluccaT2A),
            new TravelValidator(IsKhaldun),
            new TravelValidator(IsIlshenar),
............

and below that

Code:
private static readonly 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 */
/* Recall From */    { false, false, true, true, false, false, true, false, false, false, false, true, true, false, true, 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 },
/* Gate From */    { 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 },
/* Mark In */    { 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 },
/* Tele To */    { true, true, true, true, true, true, true, true, false, true, false, false, false, true, true, true, true, false, false },
};

I'd suggest adding your region to the bottom of the list for TravelValidator

find: new TravelValidator(IsMLDungeon) add a comma to the end of the line
then on the next line: new TravelValidator(IsCopyofTrammelDungeon)

now for each line /* Recall From */ etc, go to the end of last false/true, add a comma and either true or false depending on your preferences.

after that find the method: public static bool IsMLDungeon(Map map, Point3D loc) around line 890

and add something like:
Code:
public static bool IsCopyofTrammelDungeon(Map map, Point3D loc)
        {
            Region region = Region.Find(loc, map);
            return (region.IsPartOf(typeof(DungeonRegion)) && region.Map == Map.CopyofTrammel);
        }

** the region here DungeonRegion relates to what you classified the region as in Regions.xml

Now, restart and test it out.
Much, much easier than setting up custom regions in a box, right?
 
Back