Merge branch 'main' of https://git.ra3battle.cn/Kalospacer/WulaFallenEmpireRW
This commit is contained in:
@@ -24,64 +24,74 @@ namespace WulaFallenEmpire
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
Log.Message("[CompChargingBed] CompTick running.");
|
||||
|
||||
var bed = (Building_Bed)parent;
|
||||
if (!bed.AnyOccupants)
|
||||
var powerComp = parent.GetComp<CompPowerTrader>();
|
||||
|
||||
// 如果床没电,停止所有充电
|
||||
if (powerComp is { PowerOn: false })
|
||||
{
|
||||
for (int i = chargingPawns.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var p = chargingPawns[i];
|
||||
var h = p.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef);
|
||||
if (h != null)
|
||||
{
|
||||
Log.Message($"[CompChargingBed] Bed empty. Removing hediff from {p.LabelShort}.");
|
||||
p.health.RemoveHediff(h);
|
||||
}
|
||||
}
|
||||
chargingPawns.Clear();
|
||||
StopAllCharging();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentOccupants = new HashSet<Pawn>(bed.CurOccupants);
|
||||
Log.Message($"[CompChargingBed] Found {currentOccupants.Count} occupants.");
|
||||
|
||||
// 移除已经不在床上的 pawn 的充电效果
|
||||
for (int i = chargingPawns.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var pawn = chargingPawns[i];
|
||||
if (!currentOccupants.Contains(pawn))
|
||||
{
|
||||
Log.Message($"[CompChargingBed] Pawn {pawn.LabelShort} left the bed. Removing hediff.");
|
||||
var hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef);
|
||||
if (hediff != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(hediff);
|
||||
}
|
||||
StopCharging(pawn);
|
||||
chargingPawns.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 为床上的新 pawn 开始充电
|
||||
foreach (var pawn in currentOccupants)
|
||||
{
|
||||
Log.Message($"[CompChargingBed] Checking occupant: {pawn.LabelShort}.");
|
||||
bool hasNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>() != null;
|
||||
Log.Message($"[CompChargingBed] Does {pawn.LabelShort} have Need_WulaEnergy? {hasNeed}");
|
||||
|
||||
if (hasNeed)
|
||||
if (ShouldCharge(pawn) && !chargingPawns.Contains(pawn))
|
||||
{
|
||||
if (!pawn.health.hediffSet.HasHediff(Props.hediffDef))
|
||||
{
|
||||
Log.Message($"[CompChargingBed] Adding charging hediff to {pawn.LabelShort}.");
|
||||
pawn.health.AddHediff(Props.hediffDef);
|
||||
}
|
||||
if (!chargingPawns.Contains(pawn))
|
||||
{
|
||||
chargingPawns.Add(pawn);
|
||||
}
|
||||
StartCharging(pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldCharge(Pawn pawn)
|
||||
{
|
||||
return pawn.def.defName == Props.raceDefName;
|
||||
}
|
||||
|
||||
private void StartCharging(Pawn pawn)
|
||||
{
|
||||
if (pawn.health.hediffSet.HasHediff(Props.hediffDef)) return;
|
||||
pawn.health.AddHediff(Props.hediffDef);
|
||||
if (!chargingPawns.Contains(pawn))
|
||||
{
|
||||
chargingPawns.Add(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StopCharging(Pawn pawn)
|
||||
{
|
||||
var hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef);
|
||||
if (hediff != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(hediff);
|
||||
}
|
||||
}
|
||||
|
||||
private void StopAllCharging()
|
||||
{
|
||||
for (int i = chargingPawns.Count - 1; i >= 0; i--)
|
||||
{
|
||||
StopCharging(chargingPawns[i]);
|
||||
chargingPawns.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
|
||||
@@ -16,17 +16,18 @@ namespace WulaFallenEmpire
|
||||
|
||||
public override bool IsMet(out string reason)
|
||||
{
|
||||
if (!EventContext.HasVariable(name))
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
if (!eventVarManager.HasVariable(name))
|
||||
{
|
||||
EventContext.SetVariable(name, "0");
|
||||
eventVarManager.SetVariable(name, "0");
|
||||
}
|
||||
|
||||
object variable = EventContext.GetVariable<object>(name);
|
||||
object variable = eventVarManager.GetVariable<object>(name);
|
||||
|
||||
string compareValue = value;
|
||||
if (!string.IsNullOrEmpty(valueVariableName))
|
||||
{
|
||||
compareValue = EventContext.GetVariable<object>(valueVariableName)?.ToString();
|
||||
compareValue = eventVarManager.GetVariable<object>(valueVariableName)?.ToString();
|
||||
if (compareValue == null)
|
||||
{
|
||||
reason = $"Comparison variable '{valueVariableName}' not set.";
|
||||
@@ -58,17 +59,18 @@ namespace WulaFallenEmpire
|
||||
|
||||
public override bool IsMet(out string reason)
|
||||
{
|
||||
if (!EventContext.HasVariable(name))
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
if (!eventVarManager.HasVariable(name))
|
||||
{
|
||||
EventContext.SetVariable(name, 0f);
|
||||
eventVarManager.SetVariable(name, 0f);
|
||||
}
|
||||
|
||||
float variable = EventContext.GetVariable<float>(name);
|
||||
float variable = eventVarManager.GetVariable<float>(name);
|
||||
|
||||
float compareValue = value;
|
||||
if (!string.IsNullOrEmpty(valueVariableName))
|
||||
{
|
||||
compareValue = EventContext.GetVariable<float>(valueVariableName, float.NaN);
|
||||
compareValue = eventVarManager.GetVariable<float>(valueVariableName, float.NaN);
|
||||
if (float.IsNaN(compareValue))
|
||||
{
|
||||
reason = $"Comparison variable '{valueVariableName}' not set or not a number.";
|
||||
@@ -121,17 +123,18 @@ namespace WulaFallenEmpire
|
||||
|
||||
public override bool IsMet(out string reason)
|
||||
{
|
||||
if (!EventContext.HasVariable(name))
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
if (!eventVarManager.HasVariable(name))
|
||||
{
|
||||
EventContext.SetVariable(name, "0");
|
||||
eventVarManager.SetVariable(name, "0");
|
||||
}
|
||||
|
||||
object variable = EventContext.GetVariable<object>(name);
|
||||
object variable = eventVarManager.GetVariable<object>(name);
|
||||
|
||||
string compareValue = value;
|
||||
if (!string.IsNullOrEmpty(valueVariableName))
|
||||
{
|
||||
compareValue = EventContext.GetVariable<object>(valueVariableName)?.ToString();
|
||||
compareValue = eventVarManager.GetVariable<object>(valueVariableName)?.ToString();
|
||||
if (compareValue == null)
|
||||
{
|
||||
reason = $"Comparison variable '{valueVariableName}' not set.";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
@@ -11,7 +12,7 @@ namespace WulaFallenEmpire
|
||||
private EventDef def;
|
||||
private Texture2D portrait;
|
||||
private Texture2D background;
|
||||
private string selectedDescription; // Store the chosen description for this window instance
|
||||
private string selectedDescription;
|
||||
|
||||
private static EventUIConfigDef config;
|
||||
public static EventUIConfigDef Config
|
||||
@@ -34,7 +35,7 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
return def.windowSize;
|
||||
}
|
||||
return Config.defaultWindowSize; // Fallback to size from config
|
||||
return Config.defaultWindowSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,22 +46,22 @@ namespace WulaFallenEmpire
|
||||
this.absorbInputAroundWindow = true;
|
||||
this.doCloseX = true;
|
||||
|
||||
// Select the description text
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
if (!def.descriptions.NullOrEmpty())
|
||||
{
|
||||
if (def.descriptionMode == DescriptionSelectionMode.Random)
|
||||
{
|
||||
selectedDescription = def.descriptions.RandomElement();
|
||||
}
|
||||
else // Sequential
|
||||
else
|
||||
{
|
||||
string indexVarName = $"_seq_desc_index_{def.defName}";
|
||||
int currentIndex = EventContext.GetVariable<int>(indexVarName, 0);
|
||||
int currentIndex = eventVarManager.GetVariable<int>(indexVarName, 0);
|
||||
|
||||
selectedDescription = def.descriptions[currentIndex];
|
||||
|
||||
int nextIndex = (currentIndex + 1) % def.descriptions.Count;
|
||||
EventContext.SetVariable(indexVarName, nextIndex);
|
||||
eventVarManager.SetVariable(indexVarName, nextIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -85,7 +86,6 @@ namespace WulaFallenEmpire
|
||||
|
||||
HandleAction(def.immediateEffects);
|
||||
|
||||
// Append conditional descriptions
|
||||
if (!def.conditionalDescriptions.NullOrEmpty())
|
||||
{
|
||||
foreach (var condDesc in def.conditionalDescriptions)
|
||||
@@ -97,20 +97,17 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format the description AFTER immediate effects have run and conditional text is appended
|
||||
|
||||
selectedDescription = FormatDescription(selectedDescription);
|
||||
}
|
||||
|
||||
public override void DoWindowContents(Rect inRect)
|
||||
{
|
||||
// 1. Draw Background
|
||||
if (background != null)
|
||||
{
|
||||
GUI.DrawTexture(inRect, background, ScaleMode.ScaleToFit);
|
||||
}
|
||||
|
||||
// 2. Draw Top-left defName and Label
|
||||
if (Config.showDefName)
|
||||
{
|
||||
Text.Font = GameFont.Tiny;
|
||||
@@ -123,10 +120,9 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
Text.Font = Config.labelFont;
|
||||
Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label);
|
||||
Text.Font = GameFont.Small; // Reset to default
|
||||
Text.Font = GameFont.Small;
|
||||
}
|
||||
|
||||
// 3. Calculate Layout based on ConfigDef
|
||||
float virtualWidth = Config.lihuiSize.x + Config.textSize.x;
|
||||
float virtualHeight = Config.lihuiSize.y;
|
||||
|
||||
@@ -147,8 +143,6 @@ namespace WulaFallenEmpire
|
||||
float startX = (inRect.width - totalContentWidth) / 2;
|
||||
float startY = (inRect.height - totalContentHeight) / 2;
|
||||
|
||||
// 4. Draw UI Elements
|
||||
// lihui (Portrait)
|
||||
Rect lihuiRect = new Rect(startX, startY, scaledLihuiWidth, scaledLihuiHeight);
|
||||
if (portrait != null)
|
||||
{
|
||||
@@ -156,18 +150,13 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
if (Config.drawBorders)
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
Widgets.DrawBox(lihuiRect);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
// name
|
||||
Rect nameRect = new Rect(lihuiRect.xMax, lihuiRect.y, scaledNameWidth, scaledNameHeight);
|
||||
if (Config.drawBorders)
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
Widgets.DrawBox(nameRect);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Text.Font = GameFont.Medium;
|
||||
@@ -175,18 +164,14 @@ namespace WulaFallenEmpire
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
// text (Description)
|
||||
Rect textRect = new Rect(nameRect.x, nameRect.yMax + Config.textNameOffset * scale, scaledTextWidth, scaledTextHeight);
|
||||
if (Config.drawBorders)
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
Widgets.DrawBox(textRect);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
Rect textInnerRect = textRect.ContractedBy(10f * scale);
|
||||
Widgets.Label(textInnerRect, selectedDescription); // Use the selected description
|
||||
Widgets.Label(textInnerRect, selectedDescription);
|
||||
|
||||
// option (Buttons)
|
||||
Rect optionRect = new Rect(nameRect.x, textRect.yMax + Config.optionsTextOffset * scale, scaledOptionsWidth, lihuiRect.height - nameRect.height - textRect.height - (Config.textNameOffset + Config.optionsTextOffset) * scale);
|
||||
|
||||
Listing_Standard listing = new Listing_Standard();
|
||||
@@ -209,7 +194,7 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
if (option.hideWhenDisabled)
|
||||
{
|
||||
continue; // Skip rendering this option entirely
|
||||
continue;
|
||||
}
|
||||
Rect rect = listing.GetRect(30f);
|
||||
Widgets.ButtonText(rect, option.label, false, true, false);
|
||||
@@ -229,8 +214,7 @@ namespace WulaFallenEmpire
|
||||
|
||||
foreach (var ce in conditionalEffects)
|
||||
{
|
||||
string reason;
|
||||
if (AreConditionsMet(ce.conditions, out reason))
|
||||
if (AreConditionsMet(ce.conditions, out _))
|
||||
{
|
||||
if (!ce.effects.NullOrEmpty())
|
||||
{
|
||||
@@ -276,14 +260,21 @@ namespace WulaFallenEmpire
|
||||
base.PostClose();
|
||||
HandleAction(def.dismissEffects);
|
||||
}
|
||||
private string FormatDescription(string description)
|
||||
{
|
||||
var variables = EventContext.GetAllVariables();
|
||||
foreach (var variable in variables)
|
||||
{
|
||||
description = description.Replace("{" + variable.Key + "}", variable.Value.ToString());
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
private string FormatDescription(string description)
|
||||
{
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
// Use regex to find all placeholders like {variableName}
|
||||
return Regex.Replace(description, @"\{(.+?)\}", match =>
|
||||
{
|
||||
string varName = match.Groups[1].Value;
|
||||
if (eventVarManager.HasVariable(varName))
|
||||
{
|
||||
// Important: GetVariable<object> to get any type
|
||||
return eventVarManager.GetVariable<object>(varName)?.ToString() ?? "";
|
||||
}
|
||||
return match.Value; // Keep placeholder if variable not found
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
public abstract class Effect
|
||||
{
|
||||
// Allow the dialog to be null for contexts where there isn't one (like quests)
|
||||
public abstract void Execute(Dialog_CustomDisplay dialog = null);
|
||||
}
|
||||
|
||||
@@ -44,7 +43,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
if (nextDef.hiddenWindow)
|
||||
{
|
||||
// Since effects are merged in PostLoad, we only need to execute dismissEffects here.
|
||||
if (!nextDef.dismissEffects.NullOrEmpty())
|
||||
{
|
||||
foreach (var conditionalEffect in nextDef.dismissEffects)
|
||||
@@ -98,7 +96,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
||||
{
|
||||
// Only close the dialog if it exists
|
||||
dialog?.Close();
|
||||
}
|
||||
}
|
||||
@@ -174,21 +171,20 @@ namespace WulaFallenEmpire
|
||||
|
||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
||||
{
|
||||
// Only set the variable if it doesn't already exist.
|
||||
if (!EventContext.HasVariable(name))
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
if (!eventVarManager.HasVariable(name))
|
||||
{
|
||||
// Try to parse as int, then float, otherwise keep as string
|
||||
if (int.TryParse(value, out int intValue))
|
||||
{
|
||||
EventContext.SetVariable(name, intValue);
|
||||
eventVarManager.SetVariable(name, intValue);
|
||||
}
|
||||
else if (float.TryParse(value, out float floatValue))
|
||||
{
|
||||
EventContext.SetVariable(name, floatValue);
|
||||
eventVarManager.SetVariable(name, floatValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
EventContext.SetVariable(name, value);
|
||||
eventVarManager.SetVariable(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,7 +210,7 @@ namespace WulaFallenEmpire
|
||||
return;
|
||||
}
|
||||
|
||||
int goodwillChange = EventContext.GetVariable<int>(goodwillVariableName);
|
||||
int goodwillChange = Find.World.GetComponent<EventVariableManager>().GetVariable<int>(goodwillVariableName);
|
||||
Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null);
|
||||
}
|
||||
}
|
||||
@@ -238,6 +234,7 @@ namespace WulaFallenEmpire
|
||||
return;
|
||||
}
|
||||
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
List<Pawn> spawnedPawns = new List<Pawn>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -249,11 +246,11 @@ namespace WulaFallenEmpire
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
EventContext.SetVariable(storeAs, spawnedPawns.First());
|
||||
eventVarManager.SetVariable(storeAs, spawnedPawns.First());
|
||||
}
|
||||
else
|
||||
{
|
||||
EventContext.SetVariable(storeAs, spawnedPawns);
|
||||
eventVarManager.SetVariable(storeAs, spawnedPawns);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,13 +359,15 @@ namespace WulaFallenEmpire
|
||||
Log.Error("[WulaFallenEmpire] Effect_ModifyVariable has a null or empty name.");
|
||||
return;
|
||||
}
|
||||
|
||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
||||
|
||||
if (!EventContext.HasVariable(name))
|
||||
if (!eventVarManager.HasVariable(name))
|
||||
{
|
||||
EventContext.SetVariable(name, 0f);
|
||||
eventVarManager.SetVariable(name, 0f);
|
||||
}
|
||||
|
||||
float currentValue = EventContext.GetVariable<float>(name);
|
||||
float currentValue = eventVarManager.GetVariable<float>(name);
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
@@ -396,7 +395,7 @@ namespace WulaFallenEmpire
|
||||
break;
|
||||
}
|
||||
|
||||
EventContext.SetVariable(name, currentValue);
|
||||
eventVarManager.SetVariable(name, currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +410,7 @@ namespace WulaFallenEmpire
|
||||
Log.Error("[WulaFallenEmpire] Effect_ClearVariable has a null or empty name.");
|
||||
return;
|
||||
}
|
||||
EventContext.ClearVariable(name);
|
||||
Find.World.GetComponent<EventVariableManager>().ClearVariable(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +475,6 @@ namespace WulaFallenEmpire
|
||||
return;
|
||||
}
|
||||
|
||||
// If custom pawn groups are defined, use them.
|
||||
if (!pawnGroupMakers.NullOrEmpty())
|
||||
{
|
||||
IncidentParms parms = new IncidentParms
|
||||
@@ -502,102 +500,65 @@ namespace WulaFallenEmpire
|
||||
tile = map.Tile,
|
||||
points = this.points,
|
||||
faction = factionInst,
|
||||
raidStrategy = this.raidStrategy,
|
||||
seed = parms.pawnGroupMakerSeed
|
||||
};
|
||||
|
||||
if (!pawnGroupMakers.TryRandomElement(out var chosenGroupMaker))
|
||||
{
|
||||
Log.Error($"[WulaFallenEmpire] Effect_TriggerRaid could not find a suitable PawnGroupMaker for {points} points with groupKind {groupMakerParms.groupKind.defName} from the provided list.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Pawn> pawns = chosenGroupMaker.GeneratePawns(groupMakerParms).ToList();
|
||||
if (!pawns.Any())
|
||||
{
|
||||
Log.Error("[WulaFallenEmpire] Effect_TriggerRaid generated no pawns with the custom pawnGroupMakers.");
|
||||
return;
|
||||
}
|
||||
|
||||
parms.raidArrivalMode.Worker.Arrive(pawns, parms);
|
||||
|
||||
parms.raidStrategy.Worker.MakeLords(parms, pawns);
|
||||
|
||||
TaggedString finalLabel;
|
||||
if (!string.IsNullOrEmpty(this.letterLabel))
|
||||
List<Pawn> pawns = PawnGroupMakerUtility.GeneratePawns(groupMakerParms).ToList();
|
||||
if (pawns.Any())
|
||||
{
|
||||
finalLabel = this.letterLabel;
|
||||
raidArrivalMode.Worker.Arrive(pawns, parms);
|
||||
if (!string.IsNullOrEmpty(letterLabel) && !string.IsNullOrEmpty(letterText))
|
||||
{
|
||||
Find.LetterStack.ReceiveLetter(letterLabel, letterText, LetterDefOf.ThreatBig, pawns[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finalLabel = "LetterLabelRaid".Translate(factionInst.def.label).CapitalizeFirst();
|
||||
}
|
||||
|
||||
TaggedString finalText;
|
||||
if (!string.IsNullOrEmpty(this.letterText))
|
||||
{
|
||||
finalText = this.letterText;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalText = "LetterRaid".Translate(
|
||||
factionInst.Name,
|
||||
factionInst.def.pawnsPlural,
|
||||
parms.raidStrategy.arrivalTextEnemy
|
||||
).CapitalizeFirst();
|
||||
}
|
||||
|
||||
Pawn mostImportantPawn = pawns.FirstOrDefault();
|
||||
TargetInfo target = mostImportantPawn != null ? new TargetInfo(mostImportantPawn) : new TargetInfo(parms.spawnCenter, map);
|
||||
|
||||
Find.LetterStack.ReceiveLetter(finalLabel, finalText, LetterDefOf.ThreatBig, target, factionInst);
|
||||
}
|
||||
else // Fallback to default raid incident worker
|
||||
{
|
||||
IncidentParms parms = new IncidentParms
|
||||
{
|
||||
target = map,
|
||||
points = this.points,
|
||||
faction = factionInst,
|
||||
raidStrategy = this.raidStrategy,
|
||||
raidArrivalMode = this.raidArrivalMode,
|
||||
forced = true
|
||||
};
|
||||
IncidentDefOf.RaidEnemy.Worker.TryExecute(parms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Effect_CheckFactionGoodwill : Effect
|
||||
{
|
||||
public FactionDef factionDef;
|
||||
public string variableName;
|
||||
public List<Effect> successEffects;
|
||||
public List<Effect> failureEffects;
|
||||
|
||||
public override void Execute(Dialog_CustomDisplay dialog = null)
|
||||
{
|
||||
if (factionDef == null)
|
||||
{
|
||||
Log.Error("Effect_CheckFactionGoodwill requires a factionDef.");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(variableName))
|
||||
{
|
||||
Log.Error("Effect_CheckFactionGoodwill requires a variableName.");
|
||||
Log.Error("[WulaFallenEmpire] Effect_CheckFactionGoodwill has a null faction Def.");
|
||||
return;
|
||||
}
|
||||
|
||||
Faction faction = Find.FactionManager.FirstFactionOfDef(factionDef);
|
||||
if (faction == null)
|
||||
Faction targetFaction = Find.FactionManager.FirstFactionOfDef(factionDef);
|
||||
if (targetFaction == null)
|
||||
{
|
||||
// Faction doesn't exist, store a default value (e.g., 0 or a specific marker)
|
||||
EventContext.SetVariable(variableName, 0);
|
||||
Log.Warning($"Faction with def {factionDef.defName} not found. Setting '{variableName}' to 0.");
|
||||
Log.Warning($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{factionDef.defName}'.");
|
||||
ExecuteEffects(failureEffects, dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
int goodwill = faction.GoodwillWith(Faction.OfPlayer);
|
||||
EventContext.SetVariable(variableName, goodwill);
|
||||
int requiredGoodwill = Find.World.GetComponent<EventVariableManager>().GetVariable<int>(variableName);
|
||||
int currentGoodwill = Faction.OfPlayer.GoodwillWith(targetFaction);
|
||||
if (currentGoodwill >= requiredGoodwill)
|
||||
{
|
||||
ExecuteEffects(successEffects, dialog);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteEffects(failureEffects, dialog);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteEffects(List<Effect> effects, Dialog_CustomDisplay dialog)
|
||||
{
|
||||
if (effects.NullOrEmpty()) return;
|
||||
foreach (var effect in effects)
|
||||
{
|
||||
effect.Execute(dialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public static class EventContext
|
||||
{
|
||||
private static Dictionary<string, object> variables = new Dictionary<string, object>();
|
||||
|
||||
public static void SetVariable(string name, object value)
|
||||
{
|
||||
if (variables.ContainsKey(name))
|
||||
{
|
||||
variables[name] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
variables.Add(name, value);
|
||||
}
|
||||
Log.Message($"[EventContext] Set variable '{name}' to '{value}'.");
|
||||
}
|
||||
|
||||
public static T GetVariable<T>(string name, T defaultValue = default)
|
||||
{
|
||||
if (variables.TryGetValue(name, out object value))
|
||||
{
|
||||
if (value is T typedValue)
|
||||
{
|
||||
return typedValue;
|
||||
}
|
||||
// Try to convert, e.g., from int to float
|
||||
try
|
||||
{
|
||||
return (T)System.Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
Log.Warning($"[EventContext] Variable '{name}' is of type {value.GetType()} but could not be converted to {typeof(T)}.");
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
Log.Warning($"[EventContext] Variable '{name}' not found. Returning default value.");
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static bool HasVariable(string name)
|
||||
{
|
||||
return variables.ContainsKey(name);
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> GetAllVariables()
|
||||
{
|
||||
return new Dictionary<string, object>(variables);
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
variables.Clear();
|
||||
Log.Message("[EventContext] All variables cleared.");
|
||||
}
|
||||
|
||||
public static void ClearVariable(string name)
|
||||
{
|
||||
if (variables.Remove(name))
|
||||
{
|
||||
Log.Message($"[EventContext] Cleared variable '{name}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"[EventContext] Tried to clear variable '{name}' but it was not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
162
Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs
Normal file
162
Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using RimWorld;
|
||||
using RimWorld.Planet;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class EventVariableManager : WorldComponent
|
||||
{
|
||||
private Dictionary<string, int> intVars = new Dictionary<string, int>();
|
||||
private Dictionary<string, float> floatVars = new Dictionary<string, float>();
|
||||
private Dictionary<string, string> stringVars = new Dictionary<string, string>();
|
||||
private Dictionary<string, Pawn> pawnVars = new Dictionary<string, Pawn>();
|
||||
private Dictionary<string, List<Pawn>> pawnListVars = new Dictionary<string, List<Pawn>>();
|
||||
|
||||
// 用于Scribe的辅助列表
|
||||
private List<string> pawnVarKeys;
|
||||
private List<Pawn> pawnVarValues;
|
||||
private List<string> pawnListVarKeys;
|
||||
private List<List<Pawn>> pawnListVarValues;
|
||||
|
||||
// Required for WorldComponent
|
||||
public EventVariableManager(World world) : base(world)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Collections.Look(ref intVars, "intVars", LookMode.Value, LookMode.Value);
|
||||
Scribe_Collections.Look(ref floatVars, "floatVars", LookMode.Value, LookMode.Value);
|
||||
Scribe_Collections.Look(ref stringVars, "stringVars", LookMode.Value, LookMode.Value);
|
||||
Scribe_Collections.Look(ref pawnVars, "pawnVars", LookMode.Value, LookMode.Reference, ref pawnVarKeys, ref pawnVarValues);
|
||||
Scribe_Collections.Look(ref pawnListVars, "pawnListVars", LookMode.Value, LookMode.Reference, ref pawnListVarKeys, ref pawnListVarValues);
|
||||
|
||||
// Ensure dictionaries are not null after loading
|
||||
if (Scribe.mode == LoadSaveMode.PostLoadInit)
|
||||
{
|
||||
intVars ??= new Dictionary<string, int>();
|
||||
floatVars ??= new Dictionary<string, float>();
|
||||
stringVars ??= new Dictionary<string, string>();
|
||||
pawnVars ??= new Dictionary<string, Pawn>();
|
||||
pawnListVars ??= new Dictionary<string, List<Pawn>>();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(string name, object value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return;
|
||||
|
||||
// Clear any existing variable with the same name to prevent type confusion
|
||||
ClearVariable(name);
|
||||
|
||||
if (value is int intValue)
|
||||
{
|
||||
intVars[name] = intValue;
|
||||
}
|
||||
else if (value is float floatValue)
|
||||
{
|
||||
floatVars[name] = floatValue;
|
||||
}
|
||||
else if (value is string stringValue)
|
||||
{
|
||||
stringVars[name] = stringValue;
|
||||
}
|
||||
else if (value is Pawn pawnValue)
|
||||
{
|
||||
pawnVars[name] = pawnValue;
|
||||
}
|
||||
else if (value is List<Pawn> pawnListValue)
|
||||
{
|
||||
pawnListVars[name] = pawnListValue;
|
||||
}
|
||||
else if (value != null)
|
||||
{
|
||||
stringVars[name] = value.ToString();
|
||||
Log.Warning($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} was converted to string for storage. This may lead to unexpected behavior.");
|
||||
}
|
||||
}
|
||||
|
||||
public T GetVariable<T>(string name, T defaultValue = default)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return defaultValue;
|
||||
|
||||
object value = null;
|
||||
bool found = false;
|
||||
|
||||
if (typeof(T) == typeof(List<Pawn>) && pawnListVars.TryGetValue(name, out var pawnListVal))
|
||||
{
|
||||
value = pawnListVal;
|
||||
found = true;
|
||||
}
|
||||
else if (typeof(T) == typeof(Pawn) && pawnVars.TryGetValue(name, out var pawnVal))
|
||||
{
|
||||
value = pawnVal;
|
||||
found = true;
|
||||
}
|
||||
else if (typeof(T) == typeof(float) && floatVars.TryGetValue(name, out var floatVal))
|
||||
{
|
||||
value = floatVal;
|
||||
found = true;
|
||||
}
|
||||
else if (typeof(T) == typeof(int) && intVars.TryGetValue(name, out var intVal))
|
||||
{
|
||||
value = intVal;
|
||||
found = true;
|
||||
}
|
||||
else if (stringVars.TryGetValue(name, out var stringVal))
|
||||
{
|
||||
value = stringVal;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (value is T typedValue)
|
||||
{
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (T)System.Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
Log.Warning($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} could not be converted to {typeof(T)}.");
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public bool HasVariable(string name)
|
||||
{
|
||||
return intVars.ContainsKey(name) ||
|
||||
floatVars.ContainsKey(name) ||
|
||||
stringVars.ContainsKey(name) ||
|
||||
pawnVars.ContainsKey(name) ||
|
||||
pawnListVars.ContainsKey(name);
|
||||
}
|
||||
|
||||
public void ClearVariable(string name)
|
||||
{
|
||||
intVars.Remove(name);
|
||||
floatVars.Remove(name);
|
||||
stringVars.Remove(name);
|
||||
pawnVars.Remove(name);
|
||||
pawnListVars.Remove(name);
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
intVars.Clear();
|
||||
floatVars.Clear();
|
||||
stringVars.Clear();
|
||||
pawnVars.Clear();
|
||||
pawnListVars.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using HarmonyLib;
|
||||
using Verse;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
[HarmonyPatch(typeof(Pawn_HealthTracker), "get_CanBleed")]
|
||||
public static class NoBloodForWula_CanBleed_Patch
|
||||
{
|
||||
public static void Postfix(Pawn_HealthTracker __instance, ref bool __result)
|
||||
{
|
||||
// 使用反射获取Pawn_HealthTracker的私有pawn字段
|
||||
Pawn pawn = (Pawn)typeof(Pawn_HealthTracker).GetField("pawn", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);
|
||||
|
||||
if (pawn.def.defName == "WulaSpecies")
|
||||
{
|
||||
__result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Hediff_Injury), "get_BleedRate")]
|
||||
public static class NoBloodForWula_BleedRate_Patch
|
||||
{
|
||||
public static void Postfix(Hediff_Injury __instance, ref float __result)
|
||||
{
|
||||
if (__instance.pawn.def.defName == "WulaSpecies")
|
||||
{
|
||||
__result = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class JobDriver_WulaLayDownToCharge : JobDriver
|
||||
{
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
yield return Toils_Bed.GotoBed(TargetIndex.A);
|
||||
|
||||
Toil layDownAndCharge = Toils_LayDown.LayDown(TargetIndex.A, true, false, false, false);
|
||||
|
||||
layDownAndCharge.tickAction = delegate
|
||||
{
|
||||
if (pawn.IsHashIntervalTick(60))
|
||||
{
|
||||
var bed = (Building_Bed)job.targetA.Thing;
|
||||
var powerComp = bed.GetComp<CompPowerTrader>();
|
||||
|
||||
if (powerComp != null && !powerComp.PowerOn)
|
||||
{
|
||||
EndJobWith(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
|
||||
Need_WulaEnergy energyNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>();
|
||||
if (energyNeed != null && energyNeed.CurLevelPercentage >= 0.99f)
|
||||
{
|
||||
EndJobWith(JobCondition.Succeeded);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
yield return layDownAndCharge;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,60 +8,65 @@ namespace WulaFallenEmpire
|
||||
public class JobGiver_WulaGetEnergy : ThinkNode_JobGiver
|
||||
{
|
||||
public float minEnergyLevelPercentage = 0.3f;
|
||||
public float maxEnergyLevelPercentage = 0.9f;
|
||||
public float maxEnergyLevelPercentage = 1.0f;
|
||||
|
||||
public float emergencyPriority = 9.5f;
|
||||
|
||||
public override float GetPriority(Pawn pawn)
|
||||
{
|
||||
if (pawn.health.hediffSet.HasHediff(DefDatabase<HediffDef>.GetNamed("WULA_ChargingHediff")))
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] {pawn.Name.ToStringShort} already has charging hediff. Priority 0.");
|
||||
return 0f;
|
||||
}
|
||||
|
||||
Need_WulaEnergy energyNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>();
|
||||
var energyNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>();
|
||||
if (energyNeed == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
// 如果能量已充满,则不需要充电
|
||||
if (energyNeed.CurLevel >= energyNeed.MaxLevel)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
// 如果Pawn正在执行充电Job,并且能量尚未充满,则保持高优先级
|
||||
if ((pawn.CurJobDef == JobDefOf.LayDown ||
|
||||
pawn.CurJobDef == DefDatabase<JobDef>.GetNamed("WULA_IngestWulaEnergy")) &&
|
||||
energyNeed.CurLevel < energyNeed.MaxLevel)
|
||||
{
|
||||
return emergencyPriority; // 保持高优先级,直到充满
|
||||
}
|
||||
|
||||
// 如果能量低于阈值,则需要充电
|
||||
if (energyNeed.CurLevelPercentage < minEnergyLevelPercentage)
|
||||
{
|
||||
return emergencyPriority;
|
||||
}
|
||||
return 0f;
|
||||
|
||||
return 0f; // 否则,不需要充电,返回0
|
||||
}
|
||||
|
||||
protected override Job TryGiveJob(Pawn pawn)
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] Trying to give job to {pawn.Name.ToStringShort}.");
|
||||
|
||||
if (pawn.health.hediffSet.HasHediff(DefDatabase<HediffDef>.GetNamed("WULA_ChargingHediff")))
|
||||
var energyNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>();
|
||||
if (energyNeed == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (energyNeed.CurLevelPercentage >= maxEnergyLevelPercentage)
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] {pawn.Name.ToStringShort} already has charging hediff. Job cancelled.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Need_WulaEnergy energyNeed = pawn.needs.TryGetNeed<Need_WulaEnergy>();
|
||||
if (energyNeed == null || energyNeed.CurLevelPercentage >= maxEnergyLevelPercentage)
|
||||
if (!TryFindBestEnergySourceFor(pawn, out var energySource))
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] Energy level for {pawn.Name.ToStringShort} is sufficient. Job cancelled.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!TryFindBestEnergySourceFor(pawn, out Thing energySource))
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] No energy source found for {pawn.Name.ToStringShort}. Job cancelled.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (energySource is Building_Bed)
|
||||
{
|
||||
Log.Message($"[JobGiver_WulaGetEnergy] Found bed for {pawn.Name.ToStringShort}. Creating WULA_LayDownToCharge job.");
|
||||
return JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_LayDownToCharge"), energySource);
|
||||
return JobMaker.MakeJob(JobDefOf.LayDown, energySource);
|
||||
}
|
||||
|
||||
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_IngestWulaEnergy"), energySource);
|
||||
var job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_IngestWulaEnergy"), energySource);
|
||||
job.count = 1;
|
||||
return job;
|
||||
}
|
||||
@@ -109,20 +114,16 @@ namespace WulaFallenEmpire
|
||||
9999f,
|
||||
b =>
|
||||
{
|
||||
Building_Bed bed_internal = b as Building_Bed;
|
||||
if (bed_internal == null) return false;
|
||||
|
||||
var chargingComp = bed_internal.GetComp<CompChargingBed>();
|
||||
if (chargingComp == null) return false;
|
||||
if (!(b is Building_Bed bed_internal)) return false;
|
||||
|
||||
if (bed_internal.GetComp<CompChargingBed>() == null) return false;
|
||||
|
||||
var powerComp = bed_internal.GetComp<CompPowerTrader>();
|
||||
return !bed_internal.IsForbidden(pawn) &&
|
||||
pawn.CanReserve(bed_internal) &&
|
||||
!bed_internal.Medical &&
|
||||
!bed_internal.IsBurning() &&
|
||||
powerComp != null &&
|
||||
|
||||
// 使用 pawn.CanReserve 是最可靠的方法,它包含了对 ملكية، حظر، منطقة، الخ 的所有检查。
|
||||
return powerComp != null &&
|
||||
powerComp.PowerOn &&
|
||||
!bed_internal.CurOccupants.Any();
|
||||
pawn.CanReserve(bed_internal);
|
||||
}
|
||||
);
|
||||
return bed;
|
||||
|
||||
13
Source/WulaFallenEmpire/StartupLogger.cs
Normal file
13
Source/WulaFallenEmpire/StartupLogger.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public static class StartupLogger
|
||||
{
|
||||
static StartupLogger()
|
||||
{
|
||||
Log.Message("WulaFallenEmpire Mod DLL, version 1.0.2, has been loaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@
|
||||
<Compile Include="EventSystem\DelayedActionManager.cs" />
|
||||
<Compile Include="EventSystem\Dialog_CustomDisplay.cs" />
|
||||
<Compile Include="EventSystem\Effect.cs" />
|
||||
<Compile Include="EventSystem\EventContext.cs" />
|
||||
<Compile Include="EventSystem\EventVariableManager.cs" />
|
||||
<Compile Include="EventSystem\EventDef.cs" />
|
||||
<Compile Include="EventSystem\EventUIConfigDef.cs" />
|
||||
<Compile Include="EventSystem\Letter_EventChoice.cs" />
|
||||
@@ -97,6 +97,7 @@
|
||||
<Compile Include="HarmonyPatches\MechanitorUtility_InMechanitorCommandRange_Patch.cs" />
|
||||
<Compile Include="HarmonyPatches\Projectile_Launch_Patch.cs" />
|
||||
<Compile Include="HarmonyPatches\Patch_JobGiver_GatherOfferingsForPsychicRitual.cs" />
|
||||
<Compile Include="HarmonyPatches\NoBloodForWulaPatch.cs" />
|
||||
<Compile Include="HediffComp_RegenerateBackstory.cs" />
|
||||
<Compile Include="HediffComp_WulaCharging.cs" />
|
||||
<Compile Include="IngestPatch.cs" />
|
||||
@@ -104,7 +105,6 @@
|
||||
<Compile Include="JobDriver_EnterMaintenancePod.cs" />
|
||||
<Compile Include="JobDriver_HaulToMaintenancePod.cs" />
|
||||
<Compile Include="JobDriver_IngestWulaEnergy.cs" />
|
||||
<Compile Include="JobDriver_WulaLayDownToCharge.cs" />
|
||||
<Compile Include="JobGiver_WulaGetEnergy.cs" />
|
||||
<Compile Include="JobGiver_WulaPackEnergy.cs" />
|
||||
<Compile Include="Job_Maintenance.cs" />
|
||||
@@ -151,6 +151,7 @@
|
||||
<Compile Include="HediffComp_DamageResponse.cs" />
|
||||
<Compile Include="JobDefOf_WULA.cs" />
|
||||
<Compile Include="ThingDefOf_WULA.cs" />
|
||||
<Compile Include="StartupLogger.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
|
||||
Reference in New Issue
Block a user