Unstable 1.1.14.0

This commit is contained in:
Markus Isberg
2023-10-02 16:43:54 +03:00
parent 94f5a93a0c
commit cf8f0de659
606 changed files with 21906 additions and 11456 deletions
@@ -22,13 +22,13 @@ namespace Barotrauma.Abilities
private static readonly List<WeaponType> WeaponTypeValues = Enum.GetValues(typeof(WeaponType)).Cast<WeaponType>().ToList();
private readonly string itemIdentifier;
private readonly string[] tags;
private readonly Identifier[] tags;
private readonly WeaponType weapontype;
private readonly bool ignoreNonHarmfulAttacks;
public AbilityConditionAttackData(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
{
itemIdentifier = conditionElement.GetAttributeString("itemidentifier", string.Empty);
tags = conditionElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
tags = conditionElement.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>());
ignoreNonHarmfulAttacks = conditionElement.GetAttributeBool("ignorenonharmfulattacks", false);
string weaponTypeStr = conditionElement.GetAttributeString("weapontype", "Any");
@@ -41,10 +41,10 @@ namespace Barotrauma.Abilities
if (GameMain.GameSession?.Campaign?.Factions is not { } factions) { return false; }
foreach (var (factionIdentifier, amount) in mission.ReputationRewards)
foreach (var reputationReward in mission.ReputationRewards)
{
if (amount <= 0) { continue; }
if (GetMatchingFaction(factionIdentifier) is { } faction &&
if (reputationReward.Amount <= 0) { continue; }
if (GetMatchingFaction(reputationReward.FactionIdentifier) is { } faction &&
Faction.GetPlayerAffiliationStatus(faction) is FactionAffiliation.Positive)
{
return CheckMissionType();
@@ -0,0 +1,22 @@
namespace Barotrauma.Abilities
{
class AbilityConditionAllyHasTalent : AbilityConditionDataless
{
private readonly Identifier talentIdentifier;
public AbilityConditionAllyHasTalent(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
{
talentIdentifier = conditionElement.GetAttributeIdentifier("identifier", Identifier.Empty);
}
protected override bool MatchesConditionSpecific()
{
foreach (Character crewCharacter in Character.GetFriendlyCrew(characterTalent.Character))
{
if (crewCharacter.HasTalent(talentIdentifier)) { return true; }
}
return false;
}
}
}
@@ -5,12 +5,12 @@ namespace Barotrauma.Abilities
{
class AbilityConditionHasItem : AbilityConditionDataless
{
private readonly string[] tags;
private readonly Identifier[] tags;
readonly bool requireAll;
public AbilityConditionHasItem(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
{
tags = conditionElement.GetAttributeStringArray("tags", Array.Empty<string>());
tags = conditionElement.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>());
requireAll = conditionElement.GetAttributeBool("requireall", false);
}
@@ -23,7 +23,7 @@ namespace Barotrauma.Abilities
if (requireAll)
{
foreach (string tag in tags)
foreach (Identifier tag in tags)
{
if (character.GetEquippedItem(tag) == null) { return false; }
}
@@ -31,7 +31,7 @@ namespace Barotrauma.Abilities
}
else
{
foreach (string tag in tags)
foreach (Identifier tag in tags)
{
if (character.GetEquippedItem(tag) != null) { return true; }
}
@@ -5,13 +5,13 @@ namespace Barotrauma.Abilities
{
class AbilityConditionHasStatusTag : AbilityConditionDataless
{
private readonly string tag;
private readonly Identifier tag;
public AbilityConditionHasStatusTag(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
{
tag = conditionElement.GetAttributeString("tag", "");
if (string.IsNullOrEmpty(tag))
tag = conditionElement.GetAttributeIdentifier("tag", Identifier.Empty);
if (tag.IsEmpty)
{
DebugConsole.AddWarning($"Error in talent \"{characterTalent.Prefab.OriginalName}\" - tag not defined in AbilityConditionHasStatusTag.");
}
@@ -19,7 +19,7 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
if (!string.IsNullOrEmpty(tag))
if (!tag.IsEmpty)
{
return
StatusEffect.DurationList.Any(d => d.Targets.Contains(character) && d.Parent.HasTag(tag)) ||
@@ -12,8 +12,7 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
bool result = character.HasTalent(talentIdentifier);
return result;
return character.HasTalent(talentIdentifier);
}
}
}
@@ -27,8 +27,8 @@ internal sealed class AbilityConditionHoldingItem : AbilityConditionDataless
return false;
static bool HasItemInHand(Character character, Identifier? tagOrIdentifier) =>
character.GetEquippedItem(tagOrIdentifier?.Value, InvSlotType.RightHand) is not null ||
character.GetEquippedItem(tagOrIdentifier?.Value, InvSlotType.LeftHand) is not null;
character.GetEquippedItem(tagOrIdentifier, InvSlotType.RightHand) is not null ||
character.GetEquippedItem(tagOrIdentifier, InvSlotType.LeftHand) is not null;
}
}
@@ -37,10 +37,11 @@ namespace Barotrauma.Abilities
protected override void ApplyEffect()
{
if (Character?.Submarine is null) { return; }
if (Character is null) { return; }
foreach (Item item in Character.Submarine.GetItems(true))
foreach (Item item in Item.ItemList)
{
if (item.Submarine?.TeamID != Character.TeamID) { continue; }
if (item.HasTag(tags) || tags.Contains(item.Prefab.Identifier))
{
item.StatManager.ApplyStat(stat, stackable, value, CharacterTalent);
@@ -66,12 +66,12 @@
{
foreach (Character c in Character.GetFriendlyCrew(Character))
{
c?.Info.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
c?.Info?.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
}
}
else
{
Character?.Info.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
Character?.Info?.ChangeSavedStatValue(statType, value, identifier, removeOnDeath, maxValue: maxValue, setValue: setValue);
}
}
@@ -18,7 +18,7 @@ namespace Barotrauma.Abilities
protected override void ApplyEffect()
{
IEnumerable<Character> enemyCharacters = Character.CharacterList.Where(c => c.TeamID == CharacterTeamType.None);
IEnumerable<Character> enemyCharacters = Character.CharacterList.Where(c => !Character.IsFriendly(c));
int timesGiven = 0;
foreach (Character enemyCharacter in enemyCharacters)
@@ -27,7 +27,6 @@ namespace Barotrauma.Abilities
if (enemyCharacter.Submarine == null || enemyCharacter.Submarine != Submarine.MainSub) { continue; }
if (enemyCharacter.IsDead) { continue; }
if (!enemyCharacter.LockHands) { continue; }
if (timesGiven > max) { continue; }
Character.GiveMoney(moneyAmount);
GameAnalyticsManager.AddMoneyGainedEvent(moneyAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier.Value);
foreach (Character character in Character.GetFriendlyCrew(Character))
@@ -35,6 +34,7 @@ namespace Barotrauma.Abilities
character.Info?.GiveExperience(experienceAmount);
}
timesGiven++;
if (max > 0 && timesGiven >= max) { break; }
}
}
@@ -5,32 +5,43 @@ namespace Barotrauma.Abilities
{
class CharacterAbilityRegenerateLoot : CharacterAbility
{
/// <summary>
/// Chance for the loot to be regenerated. We can't use <see cref="AbilityConditionServerRandom"/> for this,
/// because it'd allow the player to reopen the container until the ability is executed successfully
/// </summary>
private readonly float randomChance;
// separate random chance used for the ability itself to prevent the player
// from opening/reopening a container until it spawns loot
private readonly float randomChance;
/// <summary>
/// Chance for an individual loot item to be generated.
/// </summary>
private readonly float randomChancePerItem = 1.0f;
// not maintained through death, so it's possible for players to respawn and re-loot chests
// seems like a minor issue for now
private readonly List<Item> openedContainers = new List<Item>();
private readonly HashSet<Item> openedContainers = new HashSet<Item>();
public CharacterAbilityRegenerateLoot(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
randomChance = abilityElement.GetAttributeFloat("randomchance", 1f);
randomChance = abilityElement.GetAttributeFloat(nameof(randomChance), 1f);
randomChancePerItem = abilityElement.GetAttributeFloat(nameof(randomChancePerItem), 1f);
}
protected override void ApplyEffect(AbilityObject abilityObject)
{
if ((abilityObject as IAbilityItem)?.Item is Item item)
{
if (openedContainers.Contains(item)) { return; }
openedContainers.Add(item);
if (randomChance < Rand.Range(0f, 1f, Rand.RandSync.Unsynced)) { return; }
if ((abilityObject as IAbilityItem)?.Item is not Item item) { return; }
if (openedContainers.Contains(item)) { return; }
if (item.GetComponent<ItemContainer>() is ItemContainer itemContainer)
{
AutoItemPlacer.RegenerateLoot(item.Submarine, itemContainer);
}
openedContainers.Add(item);
if (randomChance < Rand.Range(0f, 1f, Rand.RandSync.Unsynced)) { return; }
if (item.GetComponent<ItemContainer>() is ItemContainer itemContainer)
{
AutoItemPlacer.RegenerateLoot(item.Submarine, itemContainer, skipItemProbability: 1.0f - randomChancePerItem);
}
}
}
}
@@ -5,10 +5,10 @@ namespace Barotrauma.Abilities
class CharacterAbilityTandemFire : CharacterAbilityApplyStatusEffectsToNearestAlly
{
// this should just be its own class, misleading to inherit here
private readonly string tag;
private readonly Identifier tag;
public CharacterAbilityTandemFire(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
tag = abilityElement.GetAttributeString("tag", "");
tag = abilityElement.GetAttributeIdentifier("tag", Identifier.Empty);
}
protected override void ApplyEffect()
@@ -37,7 +37,7 @@ namespace Barotrauma.Abilities
ApplyEffectSpecific(closestCharacter);
}
static bool SelectedItemHasTag(Character character, string tag) =>
static bool SelectedItemHasTag(Character character, Identifier tag) =>
(character.SelectedItem != null && character.SelectedItem.HasTag(tag)) ||
(character.SelectedSecondaryItem != null && character.SelectedSecondaryItem.HasTag(tag));
}
@@ -133,6 +133,14 @@ namespace Barotrauma
if (IsTalentLocked(talentIdentifier)) { return false; }
if (character.Info.GetUnlockedTalentsInTree().Contains(talentIdentifier))
{
//if the character already has the talent, it must be viable?
//needed for backwards compatibility, otherwise if we remove e.g. a tier 1 or tier 2 talent,
//all the already-unlocked higher-tier talents will be considered invalid which'll break the talent selection
return true;
}
foreach (var subTree in talentTree!.TalentSubTrees)
{
if (subTree.AllTalentIdentifiers.Contains(talentIdentifier) && subTree.HasMaxTalents(selectedTalents)) { return false; }
@@ -143,11 +151,12 @@ namespace Barotrauma
{
return !talentOptionStage.HasMaxTalents(selectedTalents) && TalentTreeMeetsRequirements(talentTree, subTree, selectedTalents);
}
//if a previous stage hasn't been completed, this talent can't be selected yet
bool optionStageCompleted = talentOptionStage.HasEnoughTalents(selectedTalents);
if (!optionStageCompleted)
{
break;
}
}
}
}