Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
@@ -26,6 +26,13 @@ namespace Barotrauma
|
||||
|
||||
public readonly int BuyerCharacterInfoIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// Should the items be given to the buyer immediately, as opposed to spawning them in the sub the next round?
|
||||
/// </summary>
|
||||
public bool DeliverImmediately { get; set; }
|
||||
|
||||
public bool Delivered;
|
||||
|
||||
public PurchasedItem(ItemPrefab itemPrefab, int quantity, int buyerCharacterInfoId)
|
||||
{
|
||||
ItemPrefabIdentifier = itemPrefab.Identifier;
|
||||
@@ -216,9 +223,11 @@ namespace Barotrauma
|
||||
|
||||
public List<PurchasedItem> GetPurchasedItems(Location.StoreInfo store, bool create = false) => GetPurchasedItems(store?.Identifier ?? Identifier.Empty, create);
|
||||
|
||||
public PurchasedItem GetPurchasedItem(Identifier identifier, ItemPrefab prefab) => GetPurchasedItems(identifier)?.FirstOrDefault(i => i.ItemPrefab == prefab);
|
||||
public int GetPurchasedItemCount(Location.StoreInfo store, ItemPrefab prefab) =>
|
||||
GetPurchasedItemCount(store?.Identifier ?? Identifier.Empty, prefab);
|
||||
|
||||
public PurchasedItem GetPurchasedItem(Location.StoreInfo store, ItemPrefab prefab) => GetPurchasedItem(store?.Identifier ?? Identifier.Empty, prefab);
|
||||
public int GetPurchasedItemCount(Identifier identifier, ItemPrefab prefab) =>
|
||||
GetPurchasedItems(identifier)?.Where(i => i.ItemPrefab == prefab).Sum(it => it.Quantity) ?? 0;
|
||||
|
||||
public List<SoldItem> GetSoldItems(Identifier identifier, bool create = false) => GetItems(identifier, SoldItems, create);
|
||||
|
||||
@@ -287,23 +296,6 @@ namespace Barotrauma
|
||||
OnItemsInSellFromSubCrateChanged?.Invoke(this);
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
public void OnNewItemsPurchased(Identifier storeIdentifier, List<PurchasedItem> newItems, Client client)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int price = 0;
|
||||
Dictionary<ItemPrefab, int> buyValues = GetBuyValuesAtCurrentLocation(storeIdentifier, newItems.Select(i => i.ItemPrefab));
|
||||
foreach (PurchasedItem item in newItems)
|
||||
{
|
||||
int itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemValue, GameAnalyticsManager.MoneySink.Store, item.ItemPrefab.Identifier.Value);
|
||||
sb.Append($"\n - {item.ItemPrefab.Name} x{item.Quantity}");
|
||||
price += itemValue;
|
||||
}
|
||||
GameServer.Log($"{NetworkMember.ClientLogName(client, client?.Name ?? "Unknown")} purchased {newItems.Count} item(s) for {TextManager.FormatCurrency(price)}{sb.ToString()}", ServerLog.MessageType.Money);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void PurchaseItems(Identifier storeIdentifier, List<PurchasedItem> itemsToPurchase, bool removeFromCrate, Client client = null)
|
||||
{
|
||||
var store = Location.GetStore(storeIdentifier);
|
||||
@@ -314,27 +306,58 @@ namespace Barotrauma
|
||||
var itemsInStoreCrate = GetBuyCrateItems(storeIdentifier, create: true);
|
||||
foreach (PurchasedItem item in itemsToPurchase)
|
||||
{
|
||||
if (item.Quantity <= 0) { continue; }
|
||||
// Exchange money
|
||||
int itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||
if (!campaign.TryPurchase(client, itemValue)) { continue; }
|
||||
|
||||
// Add to the purchased items
|
||||
var purchasedItem = itemsPurchasedFromStore.Find(pi => pi.ItemPrefab == item.ItemPrefab);
|
||||
var purchasedItem = itemsPurchasedFromStore.Find(pi => pi.ItemPrefab == item.ItemPrefab && pi.DeliverImmediately == item.DeliverImmediately);
|
||||
if (purchasedItem != null)
|
||||
{
|
||||
purchasedItem.Quantity += item.Quantity;
|
||||
}
|
||||
else
|
||||
{
|
||||
purchasedItem = new PurchasedItem(item.ItemPrefab, item.Quantity, client);
|
||||
purchasedItem = new PurchasedItem(item.ItemPrefab, item.Quantity, client) { DeliverImmediately = item.DeliverImmediately };
|
||||
itemsPurchasedFromStore.Add(purchasedItem);
|
||||
}
|
||||
purchasedItem.Delivered = item.DeliverImmediately;
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemValue, GameAnalyticsManager.MoneySink.Store, item.ItemPrefab.Identifier.Value);
|
||||
}
|
||||
store.Balance += itemValue;
|
||||
if (removeFromCrate)
|
||||
}
|
||||
if (GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
Character targetCharacter;
|
||||
#if CLIENT
|
||||
targetCharacter = Character.Controlled;
|
||||
if (targetCharacter == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to deliver items directly to a character (not controlling a character).");
|
||||
}
|
||||
#else
|
||||
targetCharacter = client?.Character;
|
||||
if (targetCharacter == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to deliver items directly to a character ({(client == null ? "client was null" : $"client {client.Name} is not controlling a character")}).");
|
||||
}
|
||||
#endif
|
||||
if (targetCharacter == null)
|
||||
{
|
||||
DeliverItemsToSub(itemsToPurchase.Where(it => it.DeliverImmediately), Submarine.MainSub, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeliverItemsToCharacter(itemsToPurchase.Where(it => it.DeliverImmediately), targetCharacter, this);
|
||||
}
|
||||
|
||||
}
|
||||
if (removeFromCrate)
|
||||
{
|
||||
foreach (PurchasedItem item in itemsToPurchase)
|
||||
{
|
||||
// Remove from the shopping crate
|
||||
if (itemsInStoreCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } crateItem)
|
||||
@@ -387,9 +410,9 @@ namespace Barotrauma
|
||||
var items = new List<PurchasedItem>();
|
||||
foreach (var storeSpecificItems in PurchasedItems)
|
||||
{
|
||||
items.AddRange(storeSpecificItems.Value);
|
||||
items.AddRange(storeSpecificItems.Value.Where(it => !it.DeliverImmediately));
|
||||
}
|
||||
CreateItems(items, Submarine.MainSub, this);
|
||||
DeliverItemsToSub(items, Submarine.MainSub, this);
|
||||
PurchasedItems.Clear();
|
||||
OnPurchasedItemsChanged?.Invoke(this);
|
||||
}
|
||||
@@ -440,10 +463,22 @@ namespace Barotrauma
|
||||
if (!item.Components.All(static c => c is not Holdable { Attachable: true, Attached: true })) { return false; }
|
||||
if (!item.Components.All(static c => c is not Wire w || w.Connections.All(static c => c is null))) { return false; }
|
||||
if (!ItemAndAllContainersInteractable(item)) { return false; }
|
||||
if (item.RootContainer is Item rootContainer && rootContainer.HasTag(Tags.DontSellItems)) { return false; }
|
||||
if (!AllContainersAllowSellingItems(item)) { return false; }
|
||||
return true;
|
||||
}).Distinct();
|
||||
|
||||
static bool AllContainersAllowSellingItems(Item item)
|
||||
{
|
||||
do
|
||||
{
|
||||
item = item.Container;
|
||||
if (item is null) { return true; }
|
||||
if (item.HasTag(Tags.DontSellItems)) { return false; }
|
||||
if (item.Components.Any(static c => c.DisallowSellingItemsFromContainer)) { return false; }
|
||||
} while (item != null);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ItemAndAllContainersInteractable(Item item)
|
||||
{
|
||||
do
|
||||
@@ -501,7 +536,7 @@ namespace Barotrauma
|
||||
=> items.Where(it => it.HasTag(Tags.Crate) && !it.NonInteractable && !it.NonPlayerTeamInteractable && !it.HiddenInGame && !it.Removed && (conditional == null || conditional(it)));
|
||||
|
||||
public static IEnumerable<ItemContainer> FindReusableCargoContainers(IEnumerable<Submarine> subs, IEnumerable<Hull> cargoRooms = null) =>
|
||||
FilterCargoCrates(Item.ItemList, it => subs.Contains(it.Submarine) && (cargoRooms == null || cargoRooms.Contains(it.CurrentHull)))
|
||||
FilterCargoCrates(Item.ItemList, it => subs.Contains(it.Submarine) && !it.HasTag(Tags.CargoMissionItem) && (cargoRooms == null || cargoRooms.Contains(it.CurrentHull)))
|
||||
.Select(it => it.GetComponent<ItemContainer>())
|
||||
.Where(c => c != null);
|
||||
|
||||
@@ -553,9 +588,9 @@ namespace Barotrauma
|
||||
return itemContainer;
|
||||
}
|
||||
|
||||
public static void CreateItems(List<PurchasedItem> itemsToSpawn, Submarine sub, CargoManager cargoManager)
|
||||
public static void DeliverItemsToSub(IEnumerable<PurchasedItem> itemsToSpawn, Submarine sub, CargoManager cargoManager)
|
||||
{
|
||||
if (itemsToSpawn.Count == 0) { return; }
|
||||
if (!itemsToSpawn.Any()) { return; }
|
||||
|
||||
WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, sub);
|
||||
if (wp == null)
|
||||
@@ -571,7 +606,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub == Submarine.MainSub)
|
||||
if (sub == Submarine.MainSub && itemsToSpawn.Any(it => !it.Delivered && it.Quantity > 0))
|
||||
{
|
||||
#if CLIENT
|
||||
new GUIMessageBox("",
|
||||
@@ -597,37 +632,66 @@ namespace Barotrauma
|
||||
List<ItemContainer> availableContainers = FindReusableCargoContainers(connectedSubs, FindCargoRooms(connectedSubs)).ToList();
|
||||
foreach (PurchasedItem pi in itemsToSpawn)
|
||||
{
|
||||
pi.Delivered = true;
|
||||
Vector2 position = GetCargoPos(cargoRoom, pi.ItemPrefab);
|
||||
|
||||
for (int i = 0; i < pi.Quantity; i++)
|
||||
{
|
||||
var item = new Item(pi.ItemPrefab, position, wp.Submarine);
|
||||
var itemContainer = GetOrCreateCargoContainerFor(pi.ItemPrefab, cargoRoom, ref availableContainers);
|
||||
itemContainer?.Inventory.TryPutItem(item, null);
|
||||
var idCard = item.GetComponent<IdCard>();
|
||||
if (cargoManager != null && idCard != null && pi.BuyerCharacterInfoIdentifier != 0)
|
||||
{
|
||||
cargoManager.purchasedIDCards.Add((pi, idCard));
|
||||
}
|
||||
itemSpawned(pi, item);
|
||||
ItemSpawned(pi, item, cargoManager);
|
||||
#if SERVER
|
||||
Entity.Spawner?.CreateNetworkEvent(new EntitySpawner.SpawnEntity(item));
|
||||
#endif
|
||||
(itemContainer?.Item ?? item).AssignCampaignInteractionType(CampaignMode.InteractionType.Cargo);
|
||||
static void itemSpawned(PurchasedItem purchased, Item item)
|
||||
{
|
||||
Submarine sub = item.Submarine ?? item.RootContainer?.Submarine;
|
||||
if (sub != null)
|
||||
{
|
||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||
{
|
||||
wifiComponent.TeamID = sub.TeamID;
|
||||
}
|
||||
}
|
||||
}
|
||||
(itemContainer?.Item ?? item).AssignCampaignInteractionType(CampaignMode.InteractionType.Cargo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeliverItemsToCharacter(IEnumerable<PurchasedItem> itemsToSpawn, Character character, CargoManager cargoManager)
|
||||
{
|
||||
if (!itemsToSpawn.Any()) { return; }
|
||||
|
||||
foreach (PurchasedItem pi in itemsToSpawn)
|
||||
{
|
||||
pi.Delivered = true;
|
||||
for (int i = 0; i < pi.Quantity; i++)
|
||||
{
|
||||
var item = new Item(pi.ItemPrefab, character.Position, character.Submarine);
|
||||
#if SERVER
|
||||
Entity.Spawner?.CreateNetworkEvent(new EntitySpawner.SpawnEntity(item));
|
||||
#endif
|
||||
if (!character.Inventory.TryPutItem(item, user: null, item.AllowedSlots))
|
||||
{
|
||||
foreach (Item containedItem in character.Inventory.AllItemsMod)
|
||||
{
|
||||
if (containedItem.OwnInventory != null &&
|
||||
containedItem.OwnInventory.TryPutItem(item, user: null, item.AllowedSlots))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemSpawned(pi, item, cargoManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void ItemSpawned(PurchasedItem purchased, Item item, CargoManager cargoManager)
|
||||
{
|
||||
var idCard = item.GetComponent<IdCard>();
|
||||
if (cargoManager != null && idCard != null && purchased.BuyerCharacterInfoIdentifier != 0)
|
||||
{
|
||||
cargoManager.purchasedIDCards.Add((purchased, idCard));
|
||||
}
|
||||
|
||||
Submarine sub = item.Submarine ?? item.RootContainer?.Submarine;
|
||||
if (sub != null)
|
||||
{
|
||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||
{
|
||||
wifiComponent.TeamID = sub.TeamID;
|
||||
}
|
||||
}
|
||||
itemsToSpawn.Clear();
|
||||
}
|
||||
|
||||
private readonly List<(PurchasedItem purchaseInfo, IdCard idCard)> purchasedIDCards = new List<(PurchasedItem purchaseInfo, IdCard idCard)>();
|
||||
@@ -685,6 +749,7 @@ namespace Barotrauma
|
||||
new XAttribute("id", item.ItemPrefab.Identifier),
|
||||
new XAttribute("qty", item.Quantity),
|
||||
new XAttribute("storeid", storeSpecificItems.Key),
|
||||
new XAttribute("deliverimmediately", item.DeliverImmediately),
|
||||
new XAttribute("buyer", item.BuyerCharacterInfoIdentifier)));
|
||||
}
|
||||
}
|
||||
@@ -700,17 +765,22 @@ namespace Barotrauma
|
||||
{
|
||||
string prefabId = itemElement.GetAttributeString("id", null);
|
||||
if (string.IsNullOrWhiteSpace(prefabId)) { continue; }
|
||||
var prefab = ItemPrefab.Prefabs.Find(p => p.Identifier == prefabId);
|
||||
if (prefab == null) { continue; }
|
||||
if (!ItemPrefab.Prefabs.TryGet(prefabId.ToIdentifier(), out var prefab)) { continue; }
|
||||
int qty = itemElement.GetAttributeInt("qty", 0);
|
||||
Identifier storeId = itemElement.GetAttributeIdentifier("storeid", "merchant");
|
||||
bool deliverImmediately = itemElement.GetAttributeBool("deliverimmediately", false);
|
||||
int buyerId = itemElement.GetAttributeInt("buyer", 0);
|
||||
if (!purchasedItems.TryGetValue(storeId, out var storeItems))
|
||||
{
|
||||
storeItems = new List<PurchasedItem>();
|
||||
purchasedItems.Add(storeId, storeItems);
|
||||
}
|
||||
storeItems.Add(new PurchasedItem(prefab, qty, buyerId));
|
||||
storeItems.Add(new PurchasedItem(prefab, qty, buyerId)
|
||||
{
|
||||
DeliverImmediately = deliverImmediately,
|
||||
//must have already been delivered if we had opted for immediate delivery
|
||||
Delivered = deliverImmediately
|
||||
});
|
||||
}
|
||||
}
|
||||
SetPurchasedItems(purchasedItems);
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace Barotrauma
|
||||
foreach (var characterElement in element.Elements())
|
||||
{
|
||||
if (!characterElement.Name.ToString().Equals("character", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
CharacterInfo characterInfo = new CharacterInfo(characterElement);
|
||||
CharacterInfo characterInfo = new CharacterInfo(new ContentXElement(contentPackage: null, characterElement));
|
||||
#if CLIENT
|
||||
if (characterElement.GetAttributeBool("lastcontrolled", false)) { characterInfo.LastControlled = true; }
|
||||
characterInfo.CrewListIndex = characterElement.GetAttributeInt("crewlistindex", -1);
|
||||
@@ -262,7 +262,7 @@ namespace Barotrauma
|
||||
while (spawnWaypoints.Any() && spawnWaypoints.Count < characterInfos.Count)
|
||||
{
|
||||
spawnWaypoints.Add(spawnWaypoints[Rand.Int(spawnWaypoints.Count)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spawnWaypoints == null || !spawnWaypoints.Any())
|
||||
{
|
||||
@@ -306,15 +306,16 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
character.LoadTalents();
|
||||
character.GiveIdCardTags(new List<WayPoint>() { mainSubWaypoints[i], spawnWaypoints[i] });
|
||||
character.Info.StartItemsGiven = true;
|
||||
|
||||
character.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
character.GiveIdCardTags(spawnWaypoints[i]);
|
||||
character.Info.StartItemsGiven = true;
|
||||
if (character.Info.OrderData != null)
|
||||
{
|
||||
character.Info.ApplyOrderData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AddCharacter(character, sortCrewList: false);
|
||||
#if CLIENT
|
||||
if (IsSinglePlayer && (Character.Controlled == null || character.Info.LastControlled)) { Character.Controlled = character; }
|
||||
|
||||
@@ -45,7 +45,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Add(identifier, Convert.ChangeType(value, type, NumberFormatInfo.InvariantInfo));
|
||||
try
|
||||
{
|
||||
data.Add(identifier, Convert.ChangeType(value, type, NumberFormatInfo.InvariantInfo));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to change the type of the value \"{value}\" to {type}.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
||||
if (increase != 0 && Character.Controlled != null)
|
||||
{
|
||||
Character.Controlled.AddMessage(
|
||||
TextManager.GetWithVariable("reputationgainnotification", "[reputationname]", Location?.Name ?? Faction.Prefab.Name).Value,
|
||||
TextManager.GetWithVariable("reputationgainnotification", "[reputationname]", Location?.DisplayName ?? Faction.Prefab.Name).Value,
|
||||
increase > 0 ? GUIStyle.Green : GUIStyle.Red,
|
||||
playSound: true, Identifier, increase, lifetime: 5.0f);
|
||||
}
|
||||
|
||||
@@ -382,22 +382,28 @@ namespace Barotrauma
|
||||
currentLocation.DeselectMission(mission);
|
||||
}
|
||||
}
|
||||
if (levelData.HasBeaconStation && !levelData.IsBeaconActive)
|
||||
if (levelData.HasBeaconStation && !levelData.IsBeaconActive && Missions.None(m => m.Prefab.Type == MissionType.Beacon))
|
||||
{
|
||||
var beaconMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.Tags.Contains("beaconnoreward")).OrderBy(m => m.UintIdentifier);
|
||||
var beaconMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.IsSideObjective && m.Type == MissionType.Beacon);
|
||||
if (beaconMissionPrefabs.Any())
|
||||
{
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
var beaconMissionPrefab = ToolBox.SelectWeightedRandom(beaconMissionPrefabs, p => (float)p.Commonness, rand);
|
||||
if (!Missions.Any(m => m.Prefab.Type == beaconMissionPrefab.Type))
|
||||
var filteredMissions = beaconMissionPrefabs.Where(m => levelData.Difficulty >= m.MinLevelDifficulty && levelData.Difficulty <= m.MaxLevelDifficulty);
|
||||
if (filteredMissions.None())
|
||||
{
|
||||
extraMissions.Add(beaconMissionPrefab.Instantiate(Map.SelectedConnection.Locations, Submarine.MainSub));
|
||||
DebugConsole.AddWarning($"No suitable beacon mission found matching the level difficulty {levelData.Difficulty}. Ignoring the restriction.");
|
||||
}
|
||||
else
|
||||
{
|
||||
beaconMissionPrefabs = filteredMissions;
|
||||
}
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
var beaconMissionPrefab = ToolBox.SelectWeightedRandom(beaconMissionPrefabs, p => p.Commonness, rand);
|
||||
extraMissions.Add(beaconMissionPrefab.Instantiate(Map.SelectedConnection.Locations, Submarine.MainSub));
|
||||
}
|
||||
}
|
||||
if (levelData.HasHuntingGrounds)
|
||||
{
|
||||
var huntingGroundsMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.Tags.Contains("huntinggrounds")).OrderBy(m => m.UintIdentifier);
|
||||
var huntingGroundsMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.IsSideObjective && m.Tags.Contains("huntinggrounds")).OrderBy(m => m.UintIdentifier);
|
||||
if (!huntingGroundsMissionPrefabs.Any())
|
||||
{
|
||||
DebugConsole.AddWarning("Could not find a hunting grounds mission for the level. No mission with the tag \"huntinggrounds\" found.");
|
||||
@@ -552,8 +558,8 @@ namespace Barotrauma
|
||||
if (availableTransition == TransitionType.None)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to load a new campaign level. No available level transitions " +
|
||||
"(current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
"(current location: " + (map.CurrentLocation?.DisplayName ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.DisplayName ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
|
||||
@@ -564,8 +570,8 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to load a new campaign level. No available level transitions " +
|
||||
"(transition type: " + availableTransition + ", " +
|
||||
"current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
"current location: " + (map.CurrentLocation?.DisplayName ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.DisplayName ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
|
||||
@@ -576,8 +582,8 @@ namespace Barotrauma
|
||||
ShowCampaignUI = ForceMapUI = false;
|
||||
#endif
|
||||
DebugConsole.NewMessage("Transitioning to " + (nextLevel?.Seed ?? "null") +
|
||||
" (current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
" (current location: " + (map.CurrentLocation?.DisplayName ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.DisplayName ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ", " +
|
||||
@@ -862,6 +868,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//remove ID cards left in duffel bags
|
||||
foreach (var item in Item.ItemList.ToList())
|
||||
{
|
||||
if (item.HasTag(Tags.IdCardTag) &&
|
||||
(item.Container?.HasTag(Tags.DespawnContainer) ?? false))
|
||||
{
|
||||
item.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CharacterInfo ci in CrewManager.CharacterInfos.ToList())
|
||||
{
|
||||
if (ci.CauseOfDeath != null)
|
||||
@@ -1008,7 +1024,7 @@ namespace Barotrauma
|
||||
return ToolBox.SelectWeightedRandom(factionsList, weights, random);
|
||||
}
|
||||
|
||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, Client client = null)
|
||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, Character hirer, Client client = null)
|
||||
{
|
||||
if (characterInfo == null) { return false; }
|
||||
if (characterInfo.MinReputationToHire.factionId != Identifier.Empty)
|
||||
@@ -1018,7 +1034,8 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!TryPurchase(client, characterInfo.Salary)) { return false; }
|
||||
|
||||
if (!TryPurchase(client, HireManager.GetSalaryFor(characterInfo))) { return false; }
|
||||
characterInfo.IsNewHire = true;
|
||||
characterInfo.Title = null;
|
||||
location.RemoveHireableCharacter(characterInfo);
|
||||
@@ -1247,7 +1264,7 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.NewMessage("********* CAMPAIGN STATUS *********", Color.White);
|
||||
DebugConsole.NewMessage(" Money: " + Bank.Balance, Color.White);
|
||||
DebugConsole.NewMessage(" Current location: " + map.CurrentLocation.Name, Color.White);
|
||||
DebugConsole.NewMessage(" Current location: " + map.CurrentLocation.DisplayName, Color.White);
|
||||
|
||||
DebugConsole.NewMessage(" Available destinations: ", Color.White);
|
||||
for (int i = 0; i < map.CurrentLocation.Connections.Count; i++)
|
||||
@@ -1255,11 +1272,11 @@ namespace Barotrauma
|
||||
Location destination = map.CurrentLocation.Connections[i].OtherLocation(map.CurrentLocation);
|
||||
if (destination == map.SelectedLocation)
|
||||
{
|
||||
DebugConsole.NewMessage(" " + i + ". " + destination.Name + " [SELECTED]", Color.White);
|
||||
DebugConsole.NewMessage(" " + i + ". " + destination.DisplayName + " [SELECTED]", Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.NewMessage(" " + i + ". " + destination.Name, Color.White);
|
||||
DebugConsole.NewMessage(" " + i + ". " + destination.DisplayName, Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,7 +1308,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (NumberOfMissionsAtLocation(location) > Settings.TotalMaxMissionCount)
|
||||
{
|
||||
DebugConsole.AddWarning($"Client {sender.Name} had too many missions selected for location {location.Name}! Count was {NumberOfMissionsAtLocation(location)}. Deselecting extra missions.");
|
||||
DebugConsole.AddWarning($"Client {sender.Name} had too many missions selected for location {location.DisplayName}! Count was {NumberOfMissionsAtLocation(location)}. Deselecting extra missions.");
|
||||
foreach (Mission mission in currentLocation.SelectedMissions.Where(m => m.Locations[1] == location).Skip(Settings.TotalMaxMissionCount).ToList())
|
||||
{
|
||||
currentLocation.DeselectMission(mission);
|
||||
@@ -1344,7 +1361,7 @@ namespace Barotrauma
|
||||
var itemsToTransfer = new List<(Item item, Item container)>();
|
||||
if (PendingSubmarineSwitch != null)
|
||||
{
|
||||
var connectedSubs = currentSub.GetConnectedSubs().Where(s => s.Info.Type == SubmarineType.Player);
|
||||
var connectedSubs = currentSub.GetConnectedSubs().Where(s => s.Info.Type == SubmarineType.Player).ToHashSet();
|
||||
// Remove items from the old sub
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
@@ -1405,8 +1422,8 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
// First move the cargo containers, so that we can reuse them
|
||||
var cargoContainers = itemsToTransfer.Where(it => it.item.HasTag(Tags.Crate));
|
||||
foreach (var (item, oldContainer) in cargoContainers)
|
||||
var cargoContainers = itemsToTransfer.Where(it => it.item.HasTag(Tags.Crate)).ToHashSet();
|
||||
foreach (var (item, _) in cargoContainers)
|
||||
{
|
||||
Vector2 simPos = ConvertUnits.ToSimUnits(CargoManager.GetCargoPos(spawnHull, item.Prefab));
|
||||
item.SetTransform(simPos, 0.0f, findNewHull: false, setPrevTransform: false);
|
||||
@@ -1414,7 +1431,6 @@ namespace Barotrauma
|
||||
item.Submarine = spawnHull.Submarine;
|
||||
}
|
||||
// Then move the other items
|
||||
var cargoRooms = CargoManager.FindCargoRooms(newSub);
|
||||
List<ItemContainer> availableContainers = CargoManager.FindReusableCargoContainers(connectedSubs).ToList();
|
||||
foreach (var (item, oldContainer) in itemsToTransfer)
|
||||
{
|
||||
@@ -1444,7 +1460,7 @@ namespace Barotrauma
|
||||
newContainerName = cargoContainer.Item.Prefab.Identifier.ToString();
|
||||
}
|
||||
}
|
||||
string msg = "Item transfer log error.";
|
||||
string msg;
|
||||
if (oldContainer != null)
|
||||
{
|
||||
if (newContainer == null && oldContainer == item.Container)
|
||||
@@ -1466,6 +1482,27 @@ namespace Barotrauma
|
||||
DebugConsole.Log(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
foreach (var (item, _) in itemsToTransfer)
|
||||
{
|
||||
// This ensures that the new submarine takes ownership of
|
||||
// the items contained within the items that are being transferred directly,
|
||||
// i.e. circuit box components and wires
|
||||
PropagateSubmarineProperty(item);
|
||||
}
|
||||
|
||||
static void PropagateSubmarineProperty(Item item)
|
||||
{
|
||||
foreach (var ownedContainer in item.GetComponents<ItemContainer>())
|
||||
{
|
||||
foreach (var containedItem in ownedContainer.Inventory.AllItems)
|
||||
{
|
||||
containedItem.Submarine = item.Submarine;
|
||||
PropagateSubmarineProperty(containedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newSub.Info.NoItems = false;
|
||||
// Serialize the new sub
|
||||
PendingSubmarineSwitch = new SubmarineInfo(newSub);
|
||||
|
||||
@@ -83,6 +83,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(0.2f, IsPropertySaveable.Yes, description: "How likely it is for security to inspect player characters for stolen items when your reputation is high?")]
|
||||
public float MinStolenItemInspectionProbability { get; set; }
|
||||
|
||||
[Serialize(0.9f, IsPropertySaveable.Yes, description: "How likely it is for security to inspect player characters for stolen items when your reputation is low?")]
|
||||
public float MaxStolenItemInspectionProbability { get; set; }
|
||||
|
||||
public const int DefaultMaxMissionCount = 2;
|
||||
public const int MaxMissionCountLimit = 10;
|
||||
public const int MinMissionCountLimit = 1;
|
||||
|
||||
+6
-1
@@ -319,6 +319,7 @@ namespace Barotrauma
|
||||
foreach (var item in storeItems.Value)
|
||||
{
|
||||
msg.WriteIdentifier(item.ItemPrefabIdentifier);
|
||||
msg.WriteBoolean(item.DeliverImmediately);
|
||||
msg.WriteRangedInteger(item.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
}
|
||||
@@ -336,8 +337,12 @@ namespace Barotrauma
|
||||
for (int j = 0; j < itemCount; j++)
|
||||
{
|
||||
Identifier itemId = msg.ReadIdentifier();
|
||||
bool deliverImmediately = msg.ReadBoolean();
|
||||
#if SERVER
|
||||
if (!AllowImmediateItemDelivery(sender)) { deliverImmediately = false; }
|
||||
#endif
|
||||
int quantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
items[storeId].Add(new PurchasedItem(itemId, quantity, sender));
|
||||
items[storeId].Add(new PurchasedItem(itemId, quantity, sender) { DeliverImmediately = deliverImmediately });
|
||||
}
|
||||
}
|
||||
return items;
|
||||
|
||||
@@ -161,16 +161,18 @@ namespace Barotrauma
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
#if CLIENT
|
||||
case "gamemode": //legacy support
|
||||
case "singleplayercampaign":
|
||||
#if CLIENT
|
||||
CrewManager = new CrewManager(true);
|
||||
var campaign = SinglePlayerCampaign.Load(subElement);
|
||||
campaign.LoadNewLevel();
|
||||
GameMode = campaign;
|
||||
InitOwnedSubs(submarineInfo, ownedSubmarines);
|
||||
break;
|
||||
#else
|
||||
throw new Exception("The server cannot load a single player campaign.");
|
||||
#endif
|
||||
break;
|
||||
case "multiplayercampaign":
|
||||
CrewManager = new CrewManager(false);
|
||||
var mpCampaign = MultiPlayerCampaign.LoadNew(subElement);
|
||||
@@ -567,7 +569,7 @@ namespace Barotrauma
|
||||
if (EndLocation != null && levelData != null)
|
||||
{
|
||||
GUI.AddMessage(levelData.Biome.DisplayName, Color.Lerp(Color.CadetBlue, Color.DarkRed, levelData.Difficulty / 100.0f), 5.0f, playSound: false);
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Destination"), EndLocation.Name), Color.CadetBlue, playSound: false);
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Destination"), EndLocation.DisplayName), Color.CadetBlue, playSound: false);
|
||||
var missionsToShow = missions.Where(m => m.Prefab.ShowStartMessage);
|
||||
if (missionsToShow.Count() > 1)
|
||||
{
|
||||
@@ -582,7 +584,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Location"), StartLocation.Name), Color.CadetBlue, playSound: false);
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Location"), StartLocation.DisplayName), Color.CadetBlue, playSound: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,6 +881,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
//Clear the grids to allow for garbage collection
|
||||
Powered.Grids.Clear();
|
||||
Powered.ChangedConnections.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -20,6 +21,23 @@ namespace Barotrauma
|
||||
AvailableCharacters.Remove(character);
|
||||
}
|
||||
|
||||
public static int GetSalaryFor(IReadOnlyCollection<CharacterInfo> hires)
|
||||
{
|
||||
return hires.Sum(hire => GetSalaryFor(hire));
|
||||
}
|
||||
|
||||
public static int GetSalaryFor(CharacterInfo hire)
|
||||
{
|
||||
IEnumerable<Character> crew = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
float multiplier = 0;
|
||||
foreach (var character in crew)
|
||||
{
|
||||
multiplier += character?.Info?.GetSavedStatValueWithAll(StatTypes.HireCostMultiplier, hire.Job.Prefab.Identifier) ?? 0;
|
||||
}
|
||||
float finalMultiplier = 1f + MathF.Max(multiplier, -1f);
|
||||
return (int)(hire.Salary * finalMultiplier);
|
||||
}
|
||||
|
||||
public void GenerateCharacters(Location location, int amount)
|
||||
{
|
||||
AvailableCharacters.ForEach(c => c.Remove());
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
int price = prefab.Price.GetBuyPrice(GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation);
|
||||
int price = prefab.Price.GetBuyPrice(prefab, GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation);
|
||||
int currentLevel = GetUpgradeLevel(prefab, category);
|
||||
int newLevel = currentLevel + 1;
|
||||
|
||||
@@ -198,20 +198,23 @@ namespace Barotrauma
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (GameMain.NetworkMember)
|
||||
if (!force)
|
||||
{
|
||||
case null when Character.Controlled is { } controlled: // singleplayer
|
||||
if (!TryTakeResources(controlled)) { return; }
|
||||
break;
|
||||
case { IsClient: true }:
|
||||
if (!prefab.HasResourcesToUpgrade(Character.Controlled, newLevel)) { return; }
|
||||
break;
|
||||
case { IsServer: true } when client?.Character is { } character:
|
||||
if (!TryTakeResources(character)) { return; }
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" without a player.");
|
||||
return;
|
||||
switch (GameMain.NetworkMember)
|
||||
{
|
||||
case null when Character.Controlled is { } controlled: // singleplayer
|
||||
if (!TryTakeResources(controlled)) { return; }
|
||||
break;
|
||||
case { IsClient: true }:
|
||||
if (!prefab.HasResourcesToUpgrade(Character.Controlled, newLevel)) { return; }
|
||||
break;
|
||||
case { IsServer: true } when client?.Character is { } character:
|
||||
if (!TryTakeResources(character)) { return; }
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" without a player.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (price < 0)
|
||||
@@ -683,7 +686,8 @@ namespace Barotrauma
|
||||
{
|
||||
// automatically fix this if it ever happens?
|
||||
DebugConsole.AddWarning($"The upgrade {newUpgrade.Prefab.Name} in {target.Name} has a different level compared to other items! \n" +
|
||||
$"Expected level was ${newLevel} but got {newUpgrade.Level} instead.");
|
||||
$"Expected level was ${newLevel} but got {newUpgrade.Level} instead.",
|
||||
newUpgrade.Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user