3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
6 using System.Globalization;
23 private float deteriorationTimer;
30 private int updateDeteriorationCounter;
31 private const int UpdateDeteriorationInterval = 10;
33 private int prevSentConditionValue;
34 private string conditionSignal;
37 bool wasGoodCondition;
41 [
Serialize(0.0f,
IsPropertySaveable.Yes, description:
"How fast the condition of the item deteriorates per second."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, DecimalCount = 2)]
48 [
Serialize(0.0f,
IsPropertySaveable.Yes, description:
"Minimum initial delay before the item starts to deteriorate."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
55 [
Serialize(0.0f,
IsPropertySaveable.Yes, description:
"Maximum initial delay before the item starts to deteriorate."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
62 [
Serialize(50.0f,
IsPropertySaveable.Yes, description:
"The item won't deteriorate spontaneously if the condition is below this value. For example, if set to 10, the condition will spontaneously drop to 10 and then stop dropping (unless the item is damaged further by external factors). Percentages of max condition."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
69 [
Serialize(0f,
IsPropertySaveable.Yes, description:
"How low a traitor must get the item's condition for it to start breaking down.")]
83 [
Serialize(80.0f,
IsPropertySaveable.Yes, description:
"The condition of the item has to be below this for it to become repairable. Percentages of max condition."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
90 [
Serialize(1.0f,
IsPropertySaveable.Yes, description:
"How much faster the device can deteriorate when under stress (e.g. when operating at full speed/power)."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
97 [
Serialize(0.5f,
IsPropertySaveable.Yes, description:
"At what speed/power must the device be operating at to be considered \"under stress\"."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
104 [
Serialize(0.1f,
IsPropertySaveable.Yes, description:
"How fast the deterioration speed increases when under stress."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
111 [
Serialize(0.1f,
IsPropertySaveable.Yes, description:
"How fast the deterioration speed decreases when not under stress."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
118 [
Serialize(100.0f,
IsPropertySaveable.Yes, description:
"The amount of time it takes to fix the item with insufficient skill levels."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
125 [
Serialize(10.0f,
IsPropertySaveable.Yes, description:
"The amount of time it takes to fix the item with sufficient skill levels."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
132 private float skillRequirementMultiplier;
137 get {
return skillRequirementMultiplier; }
140 var oldValue = skillRequirementMultiplier;
141 skillRequirementMultiplier = value;
143 if (!MathUtils.NearlyEqual(oldValue, skillRequirementMultiplier))
151 private bool isTinkering;
154 get {
return isTinkering; }
157 if (isTinkering == value) {
return; }
160 if (tinkeringPowersDevices)
172 private Item currentRepairItem;
174 private float tinkeringDuration;
175 private float tinkeringStrength;
181 private bool tinkeringPowersDevices;
199 get => currentFixerAction;
200 private set { currentFixerAction = value; }
204 : base(
item, element)
216 var repairThresholdAttribute =
217 element.
Attributes().FirstOrDefault(a => a.Name.ToString().Equals(
"showrepairuithreshold", StringComparison.OrdinalIgnoreCase)) ??
218 element.
Attributes().FirstOrDefault(a => a.Name.ToString().Equals(
"airepairthreshold", StringComparison.OrdinalIgnoreCase));
219 if (repairThresholdAttribute !=
null)
221 if (
float.TryParse(repairThresholdAttribute.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out
float repairThreshold))
232 foreach (var effect
in onFailureEffects)
234 foreach (
Affliction affliction
in effect.Afflictions)
237 affliction.
Strength *= campaign.Settings.RepairFailMultiplier;
242 InitProjSpecific(element);
257 if (character ==
null) {
return false; }
264 if (
RequiredSkills.Any(s => s !=
null && s.Identifier ==
"electrical"))
268 if (MathUtils.NearlyEqual(reactor.CurrPowerConsumption, 0.0f, 0.1f)) {
return true; }
279 ApplyStatusEffectsAndCreateEntityEvent(
this, actionType, character);
280 ApplyStatusEffectsAndCreateEntityEvent(
this,
ActionType.OnUse, character);
281 if (bestRepairItem !=
null && bestRepairItem.GetComponent<
Holdable>() is
Holdable holdable)
283 ApplyStatusEffectsAndCreateEntityEvent(holdable, actionType, character);
284 ApplyStatusEffectsAndCreateEntityEvent(holdable,
ActionType.OnUse, character);
304 if (skills.Count == 0) {
return 1.0f; }
305 if (character ==
null) {
return 0.0f; }
308 float average = skillSum / skills.Count;
310 return ((average + 100.0f) / 2.0f) / 100.0f;
333 DebugConsole.ThrowError(
"Invalid repair command!");
343 Item bestRepairItem = GetBestRepairItem(character);
345 if (
CurrentFixer != character || currentFixerAction != action)
349 GameServer.Log($
"{GameServer.CharacterLogName(character)} failed to {(action == FixActions.Sabotage ? "sabotage
" : "repair
")} {item.Name}",
ServerLog.
MessageType.ItemInteraction);
355 GameServer.Log($
"{GameServer.CharacterLogName(character)} started {(action == FixActions.Sabotage ? "sabotaging
" : "repairing
")} {item.Name}",
ServerLog.
MessageType.ItemInteraction);
356 item.CreateServerEvent(
this);
357 prevLoggedFixer = character;
358 prevLoggedFixAction = action;
365 currentRepairItem = bestRepairItem;
375 tinkeringDuration =
float.MaxValue;
386 return character.
HeldItems.OrderByDescending(i => i.Prefab.AddedRepairSpeedMultiplier).FirstOrDefault();
399 item.CreateServerEvent(
this);
402 if (currentRepairItem !=
null)
404 foreach (var ic
in currentRepairItem.GetComponents<
ItemComponent>())
415 currentRepairItem =
null;
418 qteTimer = QteDuration;
420 repairSoundChannel?.FadeOutAndDispose();
421 repairSoundChannel =
null;
442 item.CreateServerEvent(
this);
448 UpdateProjSpecific(deltaTime);
454 conditionSignal = prevSentConditionValue.ToString();
481 item.CreateServerEvent(
this);
487 updateDeteriorationCounter++;
488 if (updateDeteriorationCounter >= UpdateDeteriorationInterval)
490 UpdateDeterioration(deltaTime * UpdateDeteriorationInterval);
491 updateDeteriorationCounter = 0;
508 tinkeringDuration -= deltaTime;
514 if (!CanTinker(
CurrentFixer) || tinkeringDuration <= 0f)
534 wasGoodCondition =
true;
558 if (fixDuration <= 0.0f)
588 prevLoggedFixer =
null;
593 else if (currentFixerAction ==
FixActions.Sabotage)
595 if (fixDuration <= 0.0f)
608 if (wasGoodCondition)
617 deteriorationTimer = 0.0f;
620 wasGoodCondition =
false;
627 throw new NotImplementedException(currentFixerAction.ToString());
631 private void UpdateDeterioration(
float deltaTime)
634 if (!ShouldDeteriorate()) {
return; }
641 deteriorationTimer -= deltaTime * GetDeteriorationDelayMultiplier();
643 if (deteriorationTimer <= 0.0f) {
item.CreateServerEvent(
this); }
657 private float GetMaxRepairConditionMultiplier(Character character)
659 if (character ==
null) {
return 1.0f; }
661 if (
RequiredSkills.Any(s => s !=
null && s.Identifier ==
"mechanical"))
663 return 1 + character.GetStatValue(
StatTypes.MaxRepairConditionMultiplierMechanical);
665 if (
RequiredSkills.Any(s => s !=
null && s.Identifier ==
"electrical"))
667 return 1 + character.GetStatValue(
StatTypes.MaxRepairConditionMultiplierElectrical);
672 private bool IsTinkerable(Character character)
674 if (!character.HasAbilityFlag(
AbilityFlags.CanTinker)) {
return false; }
675 if (
item.GetComponent<Engine>() !=
null) {
return true; }
676 if (
item.GetComponent<Pump>() !=
null) {
return true; }
677 if (
item.
HasTag(Tags.TurretAmmoSource)) {
return true; }
678 if (!character.HasAbilityFlag(
AbilityFlags.CanTinkerFabricatorsAndDeconstructors)) {
return false; }
679 if (
item.GetComponent<Fabricator>() !=
null) {
return true; }
680 if (
item.GetComponent<Deconstructor>() !=
null) {
return true; }
684 private Affliction GetTinkerExhaustion(Character character)
686 return character.CharacterHealth.GetAffliction(
"tinkerexhaustion");
689 private bool CanTinker(Character character)
691 if (!IsTinkerable(character)) {
return false; }
692 if (GetTinkerExhaustion(character) is Affliction tinkerExhaustion && tinkerExhaustion.
Strength <= tinkerExhaustion.Prefab.MaxStrength) {
return false; }
696 partial
void UpdateProjSpecific(
float deltaTime);
706 private bool ShouldDeteriorate()
718 if (ic is Fabricator || ic is Deconstructor)
723 else if (ic is PowerTransfer pt)
726 if (pt.Voltage > 0.1f) {
return true; }
728 else if (ic is PowerContainer pc)
731 if (Math.Abs(pc.CurrPowerConsumption) > 0.1f || Math.Abs(pc.CurrPowerOutput) > 0.1f) {
return true; }
733 else if (ic is Engine engine)
736 if (Math.Abs(engine.Force) > 1.0f) {
return true; }
738 else if (ic is Pump pump)
741 if (Math.Abs(pump.FlowPercentage) > 1.0f && pump.IsActive && pump.HasPower) {
return true; }
743 else if (ic is Reactor reactor)
746 if (reactor.Temperature > 0.1f) {
return true; }
748 else if (ic is OxygenGenerator oxyGenerator)
751 if (oxyGenerator.CurrFlow > 0.1f) {
return true; }
753 else if (ic is Powered powered && powered is not LightComponent)
755 if (powered.Voltage >= powered.MinVoltage) {
return true; }
762 private float GetDeteriorationDelayMultiplier()
766 if (ic is Engine engine)
768 return Math.Abs(engine.Force) / 100.0f;
770 else if (ic is Pump pump)
772 return Math.Abs(pump.FlowPercentage) / 100.0f;
774 else if (ic is Reactor reactor)
776 return (reactor.FissionRate + reactor.TurbineOutput) / 200.0f;
782 private void UpdateFixAnimation(Character character)
784 if (character ==
null || character.IsDead || character.IsIncapacitated) {
return; }
800 public AbilityRepairable(
Item item)
readonly AfflictionPrefab Prefab
readonly Identifier AfflictionType
Arbitrary string that is used to identify the type of the affliction.
float GetSkillLevel(string skillIdentifier)
void CheckTalents(AbilityEffectType abilityEffectType, AbilityObject abilityObject)
bool CanInteractWith(Character c, float maxDist=200.0f, bool checkVisibility=true, bool skipDistanceCheck=false)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
float GetStatValue(StatTypes statType, bool includeSaved=true)
bool HasAbilityFlag(AbilityFlags abilityFlag)
readonly AnimController AnimController
IEnumerable< Item >?? HeldItems
Items the character has in their hand slots. Doesn't return nulls and only returns items held in both...
void ApplySkillGain(Identifier skillIdentifier, float baseGain, bool gainedFromAbility=false, float maxGain=2f)
Increases the characters skill at a rate proportional to their current skill. If you want to increase...
void IncreaseSkillLevel(Identifier skillIdentifier, float increase, bool gainedFromAbility=false)
Increase the skill by a specific amount. Talents may affect the actual, final skill increase.
string? GetAttributeString(string key, string? def)
IEnumerable< XAttribute > Attributes()
static GameSession?? GameSession
static NetworkMember NetworkMember
float MaxRepairConditionMultiplier
void ApplyStatusEffects(ActionType type, float deltaTime, Character character=null, Limb limb=null, Entity useTarget=null, bool isNetworkEvent=false, Vector2? worldPosition=null)
Executes all StatusEffects of the specified type. Note that condition checks are ignored here: that s...
ItemStatManager StatManager
float ConditionPercentageRelativeToDefaultMaxCondition
Condition percentage disregarding MaxRepairConditionMultiplier (i.e. this can go above 100% if the it...
bool HasTag(Identifier tag)
float ConditionPercentage
List< ItemComponent > Components
void SendSignal(string signal, string connectionName)
float GetQualityModifier(Quality.StatType statType)
float AddedRepairSpeedMultiplier
ContentXElement ConfigElement
The base class for components holding the different functionalities of the item
void ApplyStatusEffects(ActionType type, float deltaTime, Character character=null, Limb targetLimb=null, Entity useTarget=null, Character user=null, Vector2? worldPosition=null, float afflictionMultiplier=1.0f)
ItemComponent(Item item, ContentXElement element)
readonly Dictionary< ActionType, List< StatusEffect > > statusEffectLists
readonly List< Skill > RequiredSkills
override float GetSkillMultiplier()
bool IsBelowRepairThreshold
float SabotageDeteriorationDuration
float MinDeteriorationDelay
float MaxStressDeteriorationMultiplier
float MaxDeteriorationDelay
bool CheckCharacterSuccess(Character character, Item bestRepairItem)
Check if the character manages to succesfully repair the item
float FixDurationHighSkill
override void UpdateBroken(float deltaTime, Camera cam)
void RepairBoost(bool qteSuccess)
float SkillRequirementMultiplier
float MinDeteriorationCondition
bool TinkeringPowersDevices
float StressDeteriorationDecreaseSpeed
override void OnItemLoaded()
Called when all the components of the item have been loaded. Use to initialize connections between co...
bool StopRepairing(Character character)
float StressDeteriorationIncreaseSpeed
float FixDurationLowSkill
float RepairDegreeOfSuccess(Character character, List< Skill > skills)
bool StartRepairing(Character character, FixActions action)
void ResetDeterioration()
float StressDeteriorationThreshold
float StressDeteriorationMultiplier
bool IsBelowRepairIconThreshold
void AdjustPowerConsumption(ref float powerConsumption)
override void ReceiveSignal(Signal signal, Connection connection)
float ForceDeteriorationTimer
override void Update(float deltaTime, Camera cam)
FixActions CurrentFixerAction
Repairable(Item item, ContentXElement element)
float MinSabotageCondition
static bool IsLoadedFriendlyOutpost
Is there a loaded level set, and is it a friendly outpost (FriendlyNPC or Team1). Does not take reput...
readonly Identifier Identifier
float SkillIncreasePerRepair
static SkillSettings Current
float SkillIncreasePerSabotage
Interface for entities that the clients can send events to the server
Interface for entities that the server can send events to the clients
AbilityFlags
AbilityFlags are a set of toggleable flags that can be applied to characters.
ActionType
ActionTypes define when a StatusEffect is executed.
StatTypes
StatTypes are used to alter several traits of a character. They are mostly used by talents.