Skip to content

Commit

Permalink
fix: Fixes character starting cities. (#1615)
Browse files Browse the repository at this point in the history
### Summary

- Moves starting city info from AccountHandler to CharacterCreation
- Simplifies the logic of determining the starting cities
- Adds support for Trammel & Felucca for non-young accounts
- Fixes fall through starting city for v6+ in UOR era.
- All staff are force-sent to GA.

Closes #1408
  • Loading branch information
kamronbatman authored Nov 26, 2023
1 parent a93a363 commit 674b8dc
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 94 deletions.
2 changes: 0 additions & 2 deletions Projects/UOContent.Tests/Tests/Utilities/TryParseTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Server;
using System;
using Xunit;

namespace Server.Tests.Utility;
Expand Down
29 changes: 1 addition & 28 deletions Projects/UOContent/Accounting/AccountHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,6 @@ public static class AccountHandler
private static TimeSpan DeleteDelay = TimeSpan.FromDays(7.0);
private static bool PasswordCommandEnabled;

private static CityInfo[] OldHavenStartingCities =
{
new("Yew", "The Empath Abbey", 633, 858, 0),
new("Minoc", "The Barnacle", 2476, 413, 15),
new("Britain", "Sweet Dreams Inn", 1496, 1628, 10),
new("Moonglow", "The Scholars Inn", 4408, 1168, 0),
new("Trinsic", "The Traveler's Inn", 1845, 2745, 0),
new("Magincia", "The Great Horns Tavern", 3734, 2222, 20),
new("Jhelom", "The Mercenary Inn", 1374, 3826, 0),
new("Skara Brae", "The Falconer's Inn", 618, 2234, 0),
new("Vesper", "The Ironwood Inn", 2771, 976, 0),
new("Haven", "Buckler's Hideaway", 3667, 2625, 0)
};

private static CityInfo[] StartingCities =
{
new("New Haven", "New Haven Bank", 1150168, 3667, 2625, 0),
new("Yew", "The Empath Abbey", 1075072, 633, 858, 0),
new("Minoc", "The Barnacle", 1075073, 2476, 413, 15),
new("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20),
new("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0),
new("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0),
new("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0),
new("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0),
new("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0)
};

private static Dictionary<IPAddress, int> m_IPTable;

private static char[] m_ForbiddenChars = { '<', '>', ':', '"', '/', '\\', '|', '?', '*' };
Expand Down Expand Up @@ -439,7 +412,7 @@ public static void EventSink_GameLogin(GameLoginEventArgs e)
logger.Information("Login: {NetState} Account '{Username}' at character list", e.State, un);
e.State.Account = acct;
e.Accepted = true;
e.CityInfo = TileMatrix.Pre6000ClientSupport ? OldHavenStartingCities : StartingCities;
e.CityInfo = CharacterCreation.GetStartingCities(acct);
}

if (!e.Accepted)
Expand Down
182 changes: 118 additions & 64 deletions Projects/UOContent/Misc/CharacterCreation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,111 @@ public static class CharacterCreation

private static readonly TimeSpan BadStartMessageDelay = TimeSpan.FromSeconds(3.5);

private static readonly CityInfo _newHavenInfo =
new("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel);
public static readonly CityInfo[] NewHavenInn =
{
new("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel)
};

// TODO: Verify this location (v5.0.8.3 client)
public static readonly CityInfo[] OldHavenBank =
{
new("Haven", "Haven bank", 3677, 2513, -1, Map.Trammel)
};

// Map property is not supported (Pre v6 clients)
public static readonly CityInfo[] OldHavenStartingCities =
{
new("Yew", "The Empath Abbey", 633, 858, 0),
new("Minoc", "The Barnacle", 2476, 413, 15),
new("Britain", "Sweet Dreams Inn", 1496, 1628, 10),
new("Moonglow", "The Scholars Inn", 4408, 1168, 0),
new("Trinsic", "The Traveler's Inn", 1845, 2745, 0),
new("Magincia", "The Great Horns Tavern", 3734, 2222, 20),
new("Jhelom", "The Mercenary Inn", 1374, 3826, 0),
new("Skara Brae", "The Falconer's Inn", 618, 2234, 0),
new("Vesper", "The Ironwood Inn", 2771, 976, 0),
new("Occlo", "Buckler's Hideaway", 3667, 2625, 0)
};

// TODO: Move to JSON files
public static readonly CityInfo[] FeluccaStartingCities =
{
new("Yew", "The Empath Abbey", 633, 858, 0, Map.Felucca),
new("Minoc", "The Barnacle", 2476, 413, 15, Map.Felucca),
new("Britain", "Sweet Dreams Inn", 1496, 1628, 10, Map.Felucca),
// TODO: Add New Magincia
new("Moonglow", "The Scholars Inn", 4408, 1168, 0, Map.Felucca),
new("Trinsic", "The Traveler's Inn", 1845, 2745, 0, Map.Felucca),
new("Magincia", "The Great Horns Tavern", 3734, 2222, 20, Map.Felucca),
new("Jhelom", "The Mercenary Inn", 1374, 3826, 0, Map.Felucca),
new("Skara Brae", "The Falconer's Inn", 618, 2234, 0, Map.Felucca),
new("Vesper", "The Ironwood Inn", 2771, 976, 0, Map.Felucca),
};

// TODO: Move to JSON files
public static readonly CityInfo[] TrammelStartingCities =
{
new("New Haven", "New Haven Bank", 1150168, 3667, 2625, 0, Map.Trammel),
new("Yew", "The Empath Abbey", 1075072, 633, 858, 0, Map.Trammel),
new("Minoc", "The Barnacle", 1075073, 2476, 413, 15, Map.Trammel),
new("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20, Map.Trammel),
// TODO: Add New Magincia
new("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0, Map.Trammel),
new("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0, Map.Trammel),
new("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0, Map.Trammel),
new("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0, Map.Trammel),
new("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0, Map.Trammel)
};

private static CityInfo[] _availableStartingCities;

public static CityInfo[] GetStartingCities(Account acct)
{
if (acct.Young && ExpansionInfo.CoreExpansion.MapSelectionFlags.Includes(MapSelectionFlags.Trammel))
{
return TileMatrix.Pre6000ClientSupport ? OldHavenBank : NewHavenInn;
}

return _availableStartingCities ??= ConstructAvailableStartingCities();
}

private static CityInfo[] ConstructAvailableStartingCities()
{
if (!TileMatrix.Pre6000ClientSupport)
{
return OldHavenStartingCities;
}

var availableMaps = ExpansionInfo.CoreExpansion.MapSelectionFlags;
var trammelAvailable = availableMaps.Includes(MapSelectionFlags.Trammel);
var feluccaAvailable = availableMaps.Includes(MapSelectionFlags.Felucca);

var length = (trammelAvailable ? TrammelStartingCities.Length : 0) +
(feluccaAvailable ? FeluccaStartingCities.Length : 0);

if (length == 0)
{
logger.Error("Both Felucca and Trammel are unavailable maps, therefore no starting cities are available.");
return Array.Empty<CityInfo>();
}

var cities = new CityInfo[length];
var index = 0;
if (trammelAvailable)
{
Array.Copy(TrammelStartingCities, 0, cities, index, TrammelStartingCities.Length);
index += TrammelStartingCities.Length;
}

if (feluccaAvailable)
{
Array.Copy(FeluccaStartingCities, 0, cities, index, FeluccaStartingCities.Length);
}

// TODO: Add Royal City for gargoyles

return cities;
}

public static void Initialize()
{
Expand Down Expand Up @@ -197,7 +300,7 @@ private static void EventSink_CharacterCreated(CharacterCreatedEventArgs args)
newChar.BankBox.DropItem(ticket);
}

var city = GetStartLocation(args, young);
var city = GetStartLocation(args);
newChar.MoveToWorld(city.Location, city.Map);

logger.Information(
Expand All @@ -216,22 +319,21 @@ private static void EventSink_CharacterCreated(CharacterCreatedEventArgs args)
public static bool VerifyProfession(int profession) =>
profession >= 0 && profession < ProfessionInfo.Professions.Length;

private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung)
private static CityInfo GetStartLocation(CharacterCreatedEventArgs args)
{
// We don't get the actual client version until after character creation
var post6000Supported = !TileMatrix.Pre6000ClientSupport;
var availableMaps = ExpansionInfo.CoreExpansion.MapSelectionFlags;
var m = args.Mobile;

if (Core.ML && post6000Supported && availableMaps.Includes(MapSelectionFlags.Trammel))
if (m.AccessLevel > AccessLevel.Player)
{
return _newHavenInfo;
var map = availableMaps.Includes(MapSelectionFlags.Felucca) ? Map.Felucca : Map.Trammel;
if (availableMaps.Includes(MapSelectionFlags.Felucca))
{
return new CityInfo("Green Acres", "Green Acres", 5445, 1153, 0, map);
}
}

var useHaven = isYoung;

var flags = args.State?.Flags ?? ClientFlags.None;
var m = args.Mobile;

var profession = ProfessionInfo.Professions[args.Profession];

switch (profession?.Name.ToLowerInvariant())
Expand All @@ -243,8 +345,6 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
return new CityInfo("Umbra", "Mardoth's Tower", 2114, 1301, -50, Map.Malas);
}

useHaven = true;

/*
* Unfortunately you are playing on a *NON-Age-Of-Shadows* game
* installation and cannot be transported to Malas.
Expand All @@ -254,16 +354,11 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1062205));

break;
return GetStartingCities(true)[0];

Check failure on line 357 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 357 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 357 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 357 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'
}
case "paladin":
{
if (availableMaps.Includes(MapSelectionFlags.Trammel) && post6000Supported)
{
return _newHavenInfo;
}

break;
return GetStartingCities(true)[0];

Check failure on line 361 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 361 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 361 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 361 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'
}
case "samurai":
{
Expand All @@ -277,8 +372,6 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
return new CityInfo("Samurai DE", "Haoti's Grounds", 368, 780, -1, Map.Malas);
}

useHaven = true;

/*
* Unfortunately you are playing on a *NON-Samurai-Empire* game
* installation and cannot be transported to Tokuno.
Expand All @@ -288,7 +381,7 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1063487));

break;
return GetStartingCities(true)[0];

Check failure on line 384 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 384 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 384 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 384 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'
}
case "ninja":
{
Expand All @@ -302,8 +395,6 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
return new CityInfo("Ninja DE", "Enimo's Residence", 414, 823, -1, Map.Malas);
}

useHaven = true;

/*
* Unfortunately you are playing on a *NON-Samurai-Empire* game
* installation and cannot be transported to Tokuno.
Expand All @@ -312,47 +403,10 @@ private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool is
* Haven on the Trammel facet.
*/
Timer.StartTimer(BadStartMessageDelay, () => m.SendLocalizedMessage(1063487));

break;
return GetStartingCities(true)[0];

Check failure on line 406 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 406 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 12)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 406 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'

Check failure on line 406 in Projects/UOContent/Misc/CharacterCreation.cs

View workflow job for this annotation

GitHub Actions / Build (MacOS 13)

Argument 1: cannot convert from 'bool' to 'Server.Accounting.Account'
}
}

if (post6000Supported && useHaven && availableMaps.Includes(MapSelectionFlags.Trammel))
{
// New Haven is supported, so put them there...
// Note: if your server maps don't contain New Haven, this will place
// them in the wilderness of Ocllo
return _newHavenInfo;
}

if (useHaven)
{
// New Haven is not available, so place them in Ocllo instead, if they're aiming for Haven
CityInfo oclloBank = new CityInfo("Ocllo", "Near the bank", 3677, 2513, -1, Map.Trammel);
if (availableMaps.Includes(MapSelectionFlags.Trammel))
{
return oclloBank;
}

if (availableMaps.Includes(MapSelectionFlags.Felucca))
{
oclloBank.Map = Map.Felucca;
return oclloBank;
}
}

// They're not trying to get to Haven, so use their city selection
// instead - adjusted according to available maps
if (args.City.Map == Map.Trammel && !availableMaps.Includes(MapSelectionFlags.Trammel))
{
args.City.Map = Map.Felucca;
}

if (args.City.Map == Map.Felucca && !availableMaps.Includes(MapSelectionFlags.Felucca))
{
args.City.Map = Map.Trammel;
}

return args.City;
}

Expand Down

0 comments on commit 674b8dc

Please sign in to comment.