Skip to content

Commit

Permalink
更新若干三星干员、@孤独的人和@教捐提出的明日方舟基建实际运作方式的实现
Browse files Browse the repository at this point in the history
  • Loading branch information
Funny-ppt committed Nov 16, 2023
1 parent 63b3831 commit c479eaa
Show file tree
Hide file tree
Showing 16 changed files with 211 additions and 30 deletions.
4 changes: 2 additions & 2 deletions InfrastSim/TimeDriven/Dormitory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public int Compare(OperatorBase? x, OperatorBase? y) {
if (x.DormVipPriority != y.DormVipPriority) {
return y.DormVipPriority - x.DormVipPriority;
}
if (x.Mood != y.Mood) {
return x.Mood - y.Mood < 0 ? -1 : 1;
if (x.MoodTicks != y.MoodTicks) {
return x.MoodTicks - y.MoodTicks;
}
return x.WorkingTime < y.WorkingTime ? -1 : 1;
}
Expand Down
15 changes: 11 additions & 4 deletions InfrastSim/TimeDriven/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
using System.Text.Json;

namespace InfrastSim.TimeDriven;
internal static class Helper
{
internal static class Helper {
public static bool VisibleToLookupSkill(this OperatorBase op) {
if (op.Facility == null) return false;
if (op.Facility.IsWorking) {
return !op.IsTired;
} else {
return !op.IsExausted;
}
}
public static OperatorBase? FindOp(this FacilityBase facility, string opName)
{
return facility.Operators.Where(op => op.Name == opName).FirstOrDefault();
Expand All @@ -18,13 +25,13 @@ public static bool IsOpInFacility(this Simulator simu, string name, FacilityType
/// 适用于 基建中xxx组干员的数量, 考虑红脸
/// </summary>
public static int GroupMemberCount(this Simulator simu, string group) {
return simu.WorkingOperators.Where(op => op.HasGroup(group)).Count();
return simu.OperatorsInFacility.Where(op => op.VisibleToLookupSkill() && op.HasGroup(group)).Count();
}
/// <summary>
/// 适用于 设施中xxx组干员, 考虑红脸
/// </summary>
public static IEnumerable<OperatorBase> GroupMembers(this FacilityBase facility, string group) {
return facility.WorkingOperators.Where(op => op.HasGroup(group));
return facility.Operators.Where(op => op.VisibleToLookupSkill() && op.HasGroup(group));
}
/// <summary>
/// 适用于 设施中是否有xxx组干员, 考虑红脸
Expand Down
65 changes: 47 additions & 18 deletions InfrastSim/TimeDriven/OperatorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,44 @@ public bool HasGroup(string group) =>
|| OperatorGroups.Groups.GetValueOrDefault(group)?.Contains(Name) == true;
public FacilityBase? Facility { get; internal set; } = null;

const double MinMood = 0.0;
const double MaxMood = 24.0;
public const double MaxMood = 24.0;
public const double MinMood = 0.0;
public const int MaxTicks = 8640000;
public const int MinTicks = 0;
public const long TimeSpanTicksPerSimuTick = 100000L;

static int MoodToTicks(double mood) {
return (int)(mood / MaxMood * MaxTicks);
}
static int TimeSpanToTicks(TimeSpan timeSpan, double factor = 1.0) {
return (int)(timeSpan.Ticks / TimeSpanTicksPerSimuTick * factor);
}
static TimeSpan TicksToTimeSpan(long ticks, double divide = 1.0) {
return new TimeSpan((long)(ticks * TimeSpanTicksPerSimuTick / divide));
}

public int Upgraded { get; set; } = 2;
public double Mood { get; private set; } = 24.0;
public double Mood => MoodTicks / (double)MaxTicks * MaxMood;
public int MoodTicks { get; private set; } = MaxTicks;
public void SetMood(double mood) {
Mood = Math.Clamp(mood, MinMood, MaxMood);
MoodTicks = MoodToTicks(Math.Clamp(mood, MinMood, MaxMood));
}
public void SetMood(int mood) {
MoodTicks = Math.Clamp(mood, MinTicks, MaxTicks);
}
static readonly int[] DefaultThreshold = new int[] { 0 };
public virtual int[] Thresholds => DefaultThreshold;
static readonly TimeSpan[] DefaultWorkingTimeThreshold = Array.Empty<TimeSpan>();
public virtual TimeSpan[] WorkingTimeThresholds => DefaultWorkingTimeThreshold;

public bool IsTired => Util.Equals(MinMood, Mood);
public bool IsFullOfEnergy => Util.Equals(MaxMood, Mood);
public bool IsTired => MoodTicks <= 50;
public bool IsExausted => MoodTicks == MinTicks;
public bool IsFullOfEnergy => MoodTicks == MaxTicks;
public virtual int DormVipPriority => 1;
public AggregateValue MoodConsumeRate { get; private set; } = new(1);
public AggregateValue EfficiencyModifier { get; private set; } = new();
public TimeSpan WorkingTime { get; internal set; } = TimeSpan.Zero;


public bool LeaveFacility() {
if (Facility == null) return false;
return Facility.Remove(this);
Expand All @@ -49,33 +67,40 @@ public virtual void Resolve(Simulator simu) {
public virtual void QueryInterest(Simulator simu) {
Debug.Assert(Facility != null);
if (Facility.IsWorking) {
var hours = 1000.0;
var ticks = MaxTicks; // 距离最近检查点的 ticks,除以心情消耗率即为实际ticks
if (MoodConsumeRate > 0) {
foreach (var threshold in Thresholds) {
if (Mood - threshold > Util.Epsilon) {
hours = Math.Min(hours, (Mood - threshold) / MoodConsumeRate);
}
//foreach (var threshold in Thresholds) {
// if (Mood - threshold > Util.Epsilon) {
// hours = Math.Min(hours, (Mood - threshold) / MoodConsumeRate);
// }
//}
// PS: 方舟自身的代码似乎也不检查心情过界技能的触发 @孤独的人
// 尝试保持行为和方舟一致。

if (MoodTicks > 50) {
ticks = MoodTicks - 50;
}
} else {
if (MaxMood - Mood > Util.Epsilon) {
hours = (Mood - MaxMood) / MoodConsumeRate;
if (MaxTicks > MoodTicks) {
ticks = MoodTicks - MaxTicks;
}
}
if (Facility is not Dormitory && !IsTired) {
foreach (var threshold in WorkingTimeThresholds) {
if (threshold > WorkingTime) {
hours = Math.Min(hours, (threshold - WorkingTime).TotalHours);
ticks = Math.Min(ticks, TimeSpanToTicks(threshold - WorkingTime));
}
}
}
simu.SetInterest(this, TimeSpan.FromHours(hours));
simu.SetInterest(this, TicksToTimeSpan(ticks, MoodConsumeRate));
// TEST REQUIRED: 该方法未经测试,可能有重大bug
}
}

public virtual void Update(Simulator simu, TimeElapsedInfo info) {
Debug.Assert(Facility != null);
if (Facility.IsWorking) { // 如果 Update 被调用,则 Facility 必不为null
SetMood(Mood - MoodConsumeRate * (info.TimeElapsed / TimeSpan.FromHours(1)));
MoodTicks = Math.Max(50, MoodTicks - TimeSpanToTicks(info.TimeElapsed, MoodConsumeRate));
WorkingTime += info.TimeElapsed;
}
if (IsTired) {
Expand All @@ -99,6 +124,7 @@ public void ToJson(Utf8JsonWriter writer, bool detailed = false) {
writer.WriteString("name", Name);
writer.WriteNumber("upgraded", Upgraded);
writer.WriteNumber("mood", Mood);
writer.WriteNumber("mood-internal", MoodTicks);
writer.WriteNumber("working-time", WorkingTime.Ticks);

if (detailed) {
Expand Down Expand Up @@ -127,7 +153,10 @@ public void ToJson(Utf8JsonWriter writer, bool detailed = false) {
op.Upgraded = upgraded.GetInt32();
}
if (elem.TryGetProperty("mood", out var mood)) {
op.Mood = Math.Clamp(mood.GetDouble(), MinMood, MaxMood);
op.SetMood(MoodToTicks(mood.GetDouble()));
}
if (elem.TryGetProperty("mood-internal", out var moodInternal)) {
op.SetMood(moodInternal.GetInt32());
}
if (elem.TryGetProperty("working-time", out var workingTime)) {
op.WorkingTime = new TimeSpan(workingTime.GetInt64());
Expand Down
13 changes: 13 additions & 0 deletions InfrastSim/TimeDriven/Operators/12F.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace InfrastSim.TimeDriven.Operators;
internal class _12F : OperatorBase {
public override string Name => "12F";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is Reception && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.2);
}
}
}

2 changes: 1 addition & 1 deletion InfrastSim/TimeDriven/Operators/Dusk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override void Resolve(Simulator simu) {
center.ExtraMoodModifier.SetValue(Name, -0.05);
MoodConsumeRate.SetValue(Name, 0.5);

if (Mood >= 12) {
if (MoodTicks >= 12 * 360000) {
simu.Ganzhixinxi.SetValue(Name, 10);
} else {
simu.Renjianyanhuo.SetValue(Name, 15);
Expand Down
2 changes: 1 addition & 1 deletion InfrastSim/TimeDriven/Operators/Eunectes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility?.Type == FacilityType.ControlCenter && !IsTired && Upgraded >= 2) {
if (simu.PowerStations.Any(power => power.Operators.First().Name == "Lancet-2")) {
if (simu.IsOpInFacility("Lancet-2", FacilityType.Power)) {
simu.ExtraPowerStation.SetValue(Name, 2);
}
}
Expand Down
26 changes: 26 additions & 0 deletions InfrastSim/TimeDriven/Operators/Fang.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Fang : OperatorBase {
public override string Name => "芬";

static TimeSpan[] _wtThresholds = {
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(3),
TimeSpan.FromHours(4),
TimeSpan.FromHours(5)
};
public override TimeSpan[] WorkingTimeThresholds => _wtThresholds;

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is ManufacturingStation manufacturing && !IsTired) {
var time = Math.Min(5, Math.Floor(WorkingTime / TimeSpan.FromHours(1)));
EfficiencyModifier.SetValue(Name, 0.2 + time * 0.01);
}
if (Facility is TradingStation trading && !IsTired && Upgraded >= 1) {
EfficiencyModifier.SetValue(Name, 0.3);
}
}
}

4 changes: 2 additions & 2 deletions InfrastSim/TimeDriven/Operators/Fiammetta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public void TryExchange(Dormitory dorm) {
for (int i = index + 1; i < arr.Length; i++) {
var op = arr[i];
if (!op.IsFullOfEnergy) {
SetMood(op.Mood);
op.SetMood(24);
SetMood(op.MoodTicks);
op.SetMood(MaxTicks);
break;
}
}
Expand Down
15 changes: 15 additions & 0 deletions InfrastSim/TimeDriven/Operators/Hibiscus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Hibiscus : OperatorBase {
public override string Name => "芙蓉";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is Dormitory dorm) {
dorm.SetVipMoodModifier(0.55);
}

// TODO: missing skill 2
}
}

26 changes: 26 additions & 0 deletions InfrastSim/TimeDriven/Operators/Kroos.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Kroos : OperatorBase {
public override string Name => "克洛丝";

static TimeSpan[] _wtThresholds = {
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(3),
TimeSpan.FromHours(4),
TimeSpan.FromHours(5)
};
public override TimeSpan[] WorkingTimeThresholds => _wtThresholds;

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is ManufacturingStation manufacturing && !IsTired) {
var time = Math.Min(5, Math.Floor(WorkingTime / TimeSpan.FromHours(1)));
EfficiencyModifier.SetValue(Name, 0.15 + time * 0.02);
}
if (Facility is Dormitory dorm && Upgraded >= 1) {
MoodConsumeRate.AddValue(Name, -0.7);
}
}
}

2 changes: 1 addition & 1 deletion InfrastSim/TimeDriven/Operators/Ling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override void Resolve(Simulator simu) {
});

if (Upgraded >= 2) {
if (Mood >= 12) {
if (MoodTicks >= 12 * 360000) {
simu.Renjianyanhuo.SetValue(Name, 15);
} else {
simu.Ganzhixinxi.SetValue(Name, 10);
Expand Down
16 changes: 16 additions & 0 deletions InfrastSim/TimeDriven/Operators/Melantha.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Melantha : OperatorBase {
public override string Name => "玫兰莎";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is TradingStation trading && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.25);
trading.Capacity.SetValue(Name, 1);
}

// TODO: missing skill 2
}
}

18 changes: 18 additions & 0 deletions InfrastSim/TimeDriven/Operators/NoirCorne.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace InfrastSim.TimeDriven.Operators;
internal class NoirCorne : OperatorBase {
public override string Name => "黑角";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is ManufacturingStation manufacturing && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.1);
manufacturing.Capacity.SetValue(Name, 10);
}
if (Facility is TradingStation trading && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.1);
trading.Capacity.SetValue(Name, 2);
}
}
}

15 changes: 15 additions & 0 deletions InfrastSim/TimeDriven/Operators/Rangers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Rangers : OperatorBase {
public override string Name => "巡林者";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is Office office && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.2);
}

// TODO: missing skill 2
}
}

2 changes: 1 addition & 1 deletion InfrastSim/TimeDriven/Operators/Vendela.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public override void Resolve(Simulator simu) {

if (Upgraded >= 2) {
foreach (var op in Facility.Operators) {
if (op.Mood <= 18) {
if (op.MoodTicks <= 18 * 360000) {
op.MoodConsumeRate.SetIfLesser("芬芳疗养beta", -0.1);
}
}
Expand Down
16 changes: 16 additions & 0 deletions InfrastSim/TimeDriven/Operators/Yato.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace InfrastSim.TimeDriven.Operators;
internal class Yato : OperatorBase {
public override string Name => "夜刀";

public override void Resolve(Simulator simu) {
base.Resolve(simu);

if (Facility is TradingStation trading && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.3);
}
if (Facility is ManufacturingStation manufacturing && !IsTired) {
EfficiencyModifier.SetValue(Name, 0.15);
}
}
}

0 comments on commit c479eaa

Please sign in to comment.