暂存
This commit is contained in:
Binary file not shown.
@@ -236,4 +236,94 @@
|
||||
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="BuildingBase">
|
||||
<defName>ARA_JellyVat</defName> <!-- defName is changed to reflect its purpose -->
|
||||
<label>生物质酿造池</label>
|
||||
<description>一个活体虫族器官,通过分别消化植物和肉类物质,来缓慢培育出营养丰富的阿拉克涅虫蜜。需要同时填充素食和肉类才能工作。</description>
|
||||
<thingClass>Building</thingClass>
|
||||
<graphicData>
|
||||
<texPath>Things/Building/Natural/Hive</texPath>
|
||||
<graphicClass>Graphic_Random</graphicClass>
|
||||
<drawSize>2</drawSize>
|
||||
</graphicData>
|
||||
<size>(2,2)</size>
|
||||
<tickerType>Normal</tickerType>
|
||||
<stuffCategories Inherit="False" />
|
||||
<costStuffCount>0</costStuffCount>
|
||||
<costList>
|
||||
<ARA_Carapace>50</ARA_Carapace>
|
||||
</costList>
|
||||
<castEdgeShadows>false</castEdgeShadows>
|
||||
<staticSunShadowHeight>0</staticSunShadowHeight>
|
||||
<altitudeLayer>Building</altitudeLayer>
|
||||
<passability>PassThroughOnly</passability>
|
||||
<terrainAffordanceNeeded>ARA_Creep</terrainAffordanceNeeded>
|
||||
<pathCost>50</pathCost>
|
||||
<statBases>
|
||||
<MaxHitPoints>250</MaxHitPoints>
|
||||
<WorkToBuild>2800</WorkToBuild>
|
||||
<Flammability>1.0</Flammability>
|
||||
</statBases>
|
||||
<placeWorkers>
|
||||
<li>PlaceWorker_PreventInteractionSpotOverlap</li>
|
||||
</placeWorkers>
|
||||
<fillPercent>0.8</fillPercent>
|
||||
<interactionCellOffset>(0,0,-1)</interactionCellOffset>
|
||||
<hasInteractionCell>true</hasInteractionCell>
|
||||
<designationCategory>ARA_Buildings</designationCategory>
|
||||
<uiOrder>2600</uiOrder>
|
||||
<surfaceType>Item</surfaceType>
|
||||
<building>
|
||||
<workTableRoomRole>Laboratory</workTableRoomRole>
|
||||
<workTableNotInRoomRoleFactor>0.8</workTableNotInRoomRoleFactor>
|
||||
</building>
|
||||
<comps>
|
||||
<li Class="CompProperties_Flickable"/>
|
||||
|
||||
<li Class="ArachnaeSwarm.CompProperties_MultiFuelSpawner">
|
||||
<spawnIntervalRange>
|
||||
<min>120000</min> <!-- 2天 -->
|
||||
<max>120000</max>
|
||||
</spawnIntervalRange>
|
||||
<products>
|
||||
<li>
|
||||
<thingDef>ARA_InsectJelly</thingDef>
|
||||
<count>150</count>
|
||||
</li>
|
||||
</products>
|
||||
<showMessageIfOwned>true</showMessageIfOwned>
|
||||
</li>
|
||||
|
||||
<!-- 燃料槽 1: 素食 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
|
||||
<saveKeysPrefix>veg_vat</saveKeysPrefix>
|
||||
<fuelLabel>植物原料</fuelLabel>
|
||||
<fuelFilter>
|
||||
<categories>
|
||||
<li>PlantFoodRaw</li>
|
||||
</categories>
|
||||
</fuelFilter>
|
||||
<fuelCapacity>50</fuelCapacity>
|
||||
<fuelConsumptionRate>25</fuelConsumptionRate>
|
||||
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||
</li>
|
||||
|
||||
<!-- 燃料槽 2: 肉类 -->
|
||||
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition_WithKey">
|
||||
<saveKeysPrefix>meat_vat</saveKeysPrefix>
|
||||
<fuelLabel>动物蛋白</fuelLabel>
|
||||
<fuelFilter>
|
||||
<categories>
|
||||
<li>MeatRaw</li>
|
||||
<li>AnimalProductRaw</li>
|
||||
</categories>
|
||||
</fuelFilter>
|
||||
<fuelCapacity>50</fuelCapacity>
|
||||
<fuelConsumptionRate>25</fuelConsumptionRate>
|
||||
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||
</li>
|
||||
</comps>
|
||||
|
||||
</ThingDef>
|
||||
</Defs>
|
||||
@@ -261,4 +261,5 @@
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
</Defs>
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
<ThingDef ParentName="BuildingBase">
|
||||
<defName>ARA_SmartThermostat</defName>
|
||||
<label>智能恒温器</label>
|
||||
<description>一个先进的、不耗电的温控设备。它是一个可逆的热泵,能自动制热或制冷以维持设定的目标温度。必须像制冷器一样安装在墙上。</description>
|
||||
<label>阿拉克涅纤管虫</label>
|
||||
<description>一个不耗电的温控虫虫。它是一个可逆的热泵,能自动制热或制冷以维持设定的目标温度。必须像制冷器一样安装在墙上。</description>
|
||||
<thingClass>ArachnaeSwarm.Building_SmartThermostat</thingClass> <!-- 使用我们新的建筑类 -->
|
||||
<graphicData>
|
||||
<texPath>Things/Building/Misc/TempControl/Cooler</texPath> <!-- 暂时使用制冷器的贴图 -->
|
||||
@@ -15,40 +15,50 @@
|
||||
<blockWind>true</blockWind>
|
||||
<fillPercent>1</fillPercent>
|
||||
<coversFloor>true</coversFloor>
|
||||
<blockLight>true</blockLight>
|
||||
<blockWeather>true</blockWeather>
|
||||
<castEdgeShadows>true</castEdgeShadows>
|
||||
<canOverlapZones>false</canOverlapZones>
|
||||
<staticSunShadowHeight>1.0</staticSunShadowHeight>
|
||||
<statBases>
|
||||
<WorkToBuild>2000</WorkToBuild>
|
||||
<WorkToBuild>400</WorkToBuild>
|
||||
<MaxHitPoints>100</MaxHitPoints>
|
||||
<Flammability>0.7</Flammability>
|
||||
<Flammability>1.0</Flammability>
|
||||
</statBases>
|
||||
<tickerType>Rare</tickerType>
|
||||
<costList>
|
||||
<Steel>120</Steel>
|
||||
<ComponentIndustrial>4</ComponentIndustrial>
|
||||
<ARA_Carapace>30</ARA_Carapace>
|
||||
</costList>
|
||||
<terrainAffordanceNeeded>Medium</terrainAffordanceNeeded>
|
||||
<placeWorkers>
|
||||
<li>PlaceWorker_Cooler</li> <!-- 使用制冷器的放置规则,确保它被正确地安装在墙上 -->
|
||||
<li>PlaceWorker_Vent</li>
|
||||
</placeWorkers>
|
||||
<drawPlaceWorkersWhileSelected>true</drawPlaceWorkersWhileSelected>
|
||||
<building>
|
||||
<canPlaceOverWall>true</canPlaceOverWall>
|
||||
<canExchangeVacuum>true</canExchangeVacuum>
|
||||
<isAirtight>true</isAirtight>
|
||||
</building>
|
||||
<researchPrerequisites>
|
||||
<li>AirConditioning</li>
|
||||
</researchPrerequisites>
|
||||
<designationCategory>ARA_Buildings</designationCategory>
|
||||
<comps>
|
||||
<!-- 提供开关按钮 -->
|
||||
<li Class="CompProperties_Flickable"/>
|
||||
<li Class="CompProperties_Flickable">
|
||||
<commandTexture>UI/Commands/Vent</commandTexture>
|
||||
<commandLabelKey>CommandDesignateOpenCloseVentLabel</commandLabelKey>
|
||||
<commandDescKey>CommandDesignateOpenCloseVentDesc</commandDescKey>
|
||||
</li>
|
||||
|
||||
<!-- 提供温度控制UI和逻辑 -->
|
||||
<li Class="CompProperties_TempControl">
|
||||
<!-- 这是设备的热交换功率。数值越大,制冷/制热速度越快。-->
|
||||
<energyPerSecond>21</energyPerSecond>
|
||||
<energyPerSecond>34</energyPerSecond>
|
||||
</li>
|
||||
|
||||
<li Class="CompProperties_Breakdownable"/>
|
||||
</comps>
|
||||
<designationCategory>Temperature</designationCategory>
|
||||
<researchPrerequisites>
|
||||
<li>AirConditioning</li>
|
||||
</researchPrerequisites>
|
||||
</ThingDef>
|
||||
|
||||
</Defs>
|
||||
@@ -17,7 +17,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
[StaticConstructorOnStartup]
|
||||
public class CompRefuelableNutrition : CompRefuelable
|
||||
public class CompRefuelableNutrition : CompRefuelable, IFuelSource
|
||||
{
|
||||
public float currentConsumptionRate = 0f;
|
||||
public float NutritionStored => Fuel;
|
||||
@@ -90,5 +90,13 @@ namespace ArachnaeSwarm
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public new void Notify_UsedThisTick()
|
||||
{
|
||||
if (Props.consumeFuelOnlyWhenUsed)
|
||||
{
|
||||
ConsumeFuel(Props.fuelConsumptionRate / 60000f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,10 +217,11 @@
|
||||
<Compile Include="WULA_HediffDamgeShield\Hediff_DamageShield.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="WULA_MutiFuelSpawner\IFuelSource.cs" />
|
||||
<Compile Include="WULA_MutiFuelSpawner\CompMultiFuelSpawner.cs" />
|
||||
<Compile Include="WULA_MutiFuelSpawner\CompRefuelableWithKey.cs" />
|
||||
<Compile Include="WULA_MutiFuelSpawner\Patch_CompRefuelableWithKey.cs" />
|
||||
<Compile Include="WULA_MutiFuelSpawner\Utility.cs" />
|
||||
<Compile Include="WULA_MutiFuelSpawner\CompRefuelableNutrition_WithKey.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace ArachnaeSwarm
|
||||
public int count = 1;
|
||||
}
|
||||
|
||||
// --- Properties Class ---
|
||||
public class CompProperties_MultiFuelSpawner : CompProperties
|
||||
{
|
||||
public List<SpawnerProduct> products;
|
||||
@@ -26,11 +25,10 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// --- Component Class ---
|
||||
public class CompMultiFuelSpawner : ThingComp
|
||||
{
|
||||
private int ticksUntilSpawn;
|
||||
private List<CompRefuelableWithKey> fuelComps;
|
||||
private List<IFuelSource> fuelComps; // Changed to use the interface
|
||||
|
||||
public CompProperties_MultiFuelSpawner Props => (CompProperties_MultiFuelSpawner)props;
|
||||
|
||||
@@ -41,7 +39,8 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
ResetCountdown();
|
||||
}
|
||||
fuelComps = parent.GetComps<CompRefuelableWithKey>().ToList();
|
||||
// Find all components that implement our interface
|
||||
fuelComps = parent.GetComps<ThingComp>().OfType<IFuelSource>().ToList();
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
@@ -56,6 +55,7 @@ namespace ArachnaeSwarm
|
||||
|
||||
if (fuelComps.NullOrEmpty()) return;
|
||||
|
||||
// Check if all fuel sources have fuel
|
||||
bool allFuelsOk = fuelComps.All(c => c.HasFuel);
|
||||
|
||||
if (allFuelsOk && (parent.GetComp<CompPowerTrader>()?.PowerOn ?? true))
|
||||
@@ -63,6 +63,7 @@ namespace ArachnaeSwarm
|
||||
ticksUntilSpawn--;
|
||||
if (ticksUntilSpawn <= 0)
|
||||
{
|
||||
// Consume fuel from all sources
|
||||
foreach (var comp in fuelComps)
|
||||
{
|
||||
comp.Notify_UsedThisTick();
|
||||
@@ -112,7 +113,7 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
string text = base.CompInspectStringExtra();
|
||||
|
||||
if (fuelComps.All(c => c.HasFuel))
|
||||
if (!fuelComps.NullOrEmpty() && fuelComps.All(c => c.HasFuel))
|
||||
{
|
||||
if (!text.NullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_RefuelableNutrition_WithKey : CompProperties_RefuelableNutrition
|
||||
{
|
||||
public string saveKeysPrefix;
|
||||
|
||||
public CompProperties_RefuelableNutrition_WithKey()
|
||||
{
|
||||
compClass = typeof(CompRefuelableNutrition_WithKey);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompRefuelableNutrition_WithKey : CompRefuelableNutrition, IFuelSource
|
||||
{
|
||||
public new CompProperties_RefuelableNutrition_WithKey Props => (CompProperties_RefuelableNutrition_WithKey)props;
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
string prefix = Props.saveKeysPrefix;
|
||||
if (prefix.NullOrEmpty())
|
||||
{
|
||||
Log.ErrorOnce($"CompRefuelableNutrition_WithKey on {parent.def.defName} has a null or empty saveKeysPrefix. Defaulting to standard save.", GetHashCode());
|
||||
base.PostExposeData();
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Accessing private fields from CompRefuelable (base of CompRefuelableNutrition) ---
|
||||
FieldInfo fuelField = AccessTools.Field(typeof(CompRefuelable), "fuel");
|
||||
FieldInfo configuredTargetFuelLevelField = AccessTools.Field(typeof(CompRefuelable), "configuredTargetFuelLevel");
|
||||
FieldInfo allowAutoRefuelField = AccessTools.Field(typeof(CompRefuelable), "allowAutoRefuel");
|
||||
|
||||
// Get current values
|
||||
float currentFuel = (float)fuelField.GetValue(this);
|
||||
float currentConfiguredLevel = (float)configuredTargetFuelLevelField.GetValue(this);
|
||||
bool currentAllowAuto = (bool)allowAutoRefuelField.GetValue(this);
|
||||
|
||||
// Scribe with prefix
|
||||
Scribe_Values.Look(ref currentFuel, prefix + "_fuel", 0f);
|
||||
Scribe_Values.Look(ref currentConfiguredLevel, prefix + "_configuredTargetFuelLevel", -1f);
|
||||
Scribe_Values.Look(ref currentAllowAuto, prefix + "_allowAutoRefuel", true);
|
||||
|
||||
// Set values back if loading
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
fuelField.SetValue(this, currentFuel);
|
||||
configuredTargetFuelLevelField.SetValue(this, currentConfiguredLevel);
|
||||
allowAutoRefuelField.SetValue(this, currentAllowAuto);
|
||||
}
|
||||
|
||||
// --- Accessing private fields from CompRefuelableNutrition ---
|
||||
// (Assuming there are any. If not, this part is not needed)
|
||||
// Example:
|
||||
// FieldInfo someOtherField = AccessTools.Field(typeof(CompRefuelableNutrition), "someOtherPrivateField");
|
||||
// ... and so on
|
||||
}
|
||||
|
||||
// We already have Notify_UsedThisTick from the previous step.
|
||||
// If not, we would add it here.
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
// 1. New Properties class that adds the save key
|
||||
public class CompProperties_RefuelableWithKey : CompProperties_Refuelable
|
||||
{
|
||||
public string saveKeysPrefix;
|
||||
@@ -14,11 +13,16 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
}
|
||||
|
||||
// 2. New Component class. It's empty for now.
|
||||
// Its purpose is to be a safe target for our Harmony patch.
|
||||
public class CompRefuelableWithKey : CompRefuelable
|
||||
public class CompRefuelableWithKey : CompRefuelable, IFuelSource
|
||||
{
|
||||
// We will override PostExposeData using a Harmony patch
|
||||
// to avoid re-implementing the entire class.
|
||||
public new CompProperties_RefuelableWithKey Props => (CompProperties_RefuelableWithKey)props;
|
||||
|
||||
public new void Notify_UsedThisTick()
|
||||
{
|
||||
if (Props.consumeFuelOnlyWhenUsed)
|
||||
{
|
||||
ConsumeFuel(Props.fuelConsumptionRate / 60000f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Source/ArachnaeSwarm/WULA_MutiFuelSpawner/IFuelSource.cs
Normal file
8
Source/ArachnaeSwarm/WULA_MutiFuelSpawner/IFuelSource.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public interface IFuelSource
|
||||
{
|
||||
bool HasFuel { get; }
|
||||
void Notify_UsedThisTick();
|
||||
}
|
||||
}
|
||||
@@ -5,46 +5,38 @@ using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
// We patch the base class method
|
||||
[HarmonyPatch(typeof(CompRefuelable), "PostExposeData")]
|
||||
public static class Patch_CompRefuelableWithKey_PostExposeData
|
||||
{
|
||||
public static bool Prefix(CompRefuelable __instance)
|
||||
{
|
||||
// But we only act if the instance is our custom subclass
|
||||
if (!(__instance is CompRefuelableWithKey refuelableWithKey))
|
||||
{
|
||||
// If it's not our class, run the original method
|
||||
return true;
|
||||
return true; // If it's not our class, run the original method
|
||||
}
|
||||
|
||||
// Get the private fields from the base CompRefuelable class using reflection
|
||||
FieldInfo fuelField = AccessTools.Field(typeof(CompRefuelable), "fuel");
|
||||
FieldInfo configuredTargetFuelLevelField = AccessTools.Field(typeof(CompRefuelable), "configuredTargetFuelLevel");
|
||||
FieldInfo allowAutoRefuelField = AccessTools.Field(typeof(CompRefuelable), "allowAutoRefuel");
|
||||
|
||||
// Get the props from our custom component
|
||||
var props = (CompProperties_RefuelableWithKey)refuelableWithKey.Props;
|
||||
string prefix = props.saveKeysPrefix;
|
||||
|
||||
if (prefix.NullOrEmpty())
|
||||
{
|
||||
Log.ErrorOnce($"CompRefuelableWithKey on {refuelableWithKey.parent.def.defName} has a null or empty saveKeysPrefix. Defaulting to standard save.", refuelableWithKey.GetHashCode());
|
||||
// If no prefix, let the original method run
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use reflection to get/set private fields from the base class
|
||||
FieldInfo fuelField = AccessTools.Field(typeof(CompRefuelable), "fuel");
|
||||
FieldInfo configuredTargetFuelLevelField = AccessTools.Field(typeof(CompRefuelable), "configuredTargetFuelLevel");
|
||||
FieldInfo allowAutoRefuelField = AccessTools.Field(typeof(CompRefuelable), "allowAutoRefuel");
|
||||
|
||||
// Get current values from the instance
|
||||
float fuel = (float)fuelField.GetValue(refuelableWithKey);
|
||||
float configuredTargetFuelLevel = (float)configuredTargetFuelLevelField.GetValue(refuelableWithKey);
|
||||
bool allowAutoRefuel = (bool)allowAutoRefuelField.GetValue(refuelableWithKey);
|
||||
|
||||
// Scribe the values with our prefix
|
||||
Scribe_Values.Look(ref fuel, prefix + "_fuel", 0f);
|
||||
Scribe_Values.Look(ref configuredTargetFuelLevel, prefix + "_configuredTargetFuelLevel", -1f);
|
||||
Scribe_Values.Look(ref allowAutoRefuel, prefix + "_allowAutoRefuel", true);
|
||||
|
||||
// Set the new values back to the instance
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
fuelField.SetValue(refuelableWithKey, fuel);
|
||||
@@ -52,8 +44,7 @@ namespace ArachnaeSwarm
|
||||
allowAutoRefuelField.SetValue(refuelableWithKey, allowAutoRefuel);
|
||||
}
|
||||
|
||||
// Prevent the original PostExposeData from running
|
||||
return false;
|
||||
return false; // Prevent the original PostExposeData from running
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public static class Lifespan_Utility
|
||||
{
|
||||
public static IEnumerable<ThoughtDef> deathThought = new List<ThoughtDef>
|
||||
{
|
||||
ThoughtDefOf.KnowColonistDied,
|
||||
ThoughtDefOf.PawnWithGoodOpinionDied,
|
||||
ThoughtDefOf.WitnessedDeathFamily,
|
||||
ThoughtDefOf.WitnessedDeathAlly,
|
||||
};
|
||||
|
||||
public static bool IsDeathThought(this ThoughtDef tDef)
|
||||
{
|
||||
return (deathThought.Contains(tDef));
|
||||
}
|
||||
|
||||
public static Thing ThingInCaseOfDeath(Pawn p)
|
||||
{
|
||||
Thing refThing;
|
||||
if (p.Dead)
|
||||
{
|
||||
if (p.Corpse == null)
|
||||
return null;
|
||||
refThing = p.Corpse;
|
||||
}
|
||||
else
|
||||
refThing = p;
|
||||
|
||||
return refThing;
|
||||
}
|
||||
|
||||
public static void TrySpawnFilth(Thing refT, float filthRadius, ThingDef filthDef)
|
||||
{
|
||||
if (
|
||||
refT.Map != null
|
||||
&& CellFinder.TryFindRandomReachableNearbyCell(
|
||||
refT.Position,
|
||||
refT.Map,
|
||||
filthRadius,
|
||||
TraverseParms.For(TraverseMode.NoPassClosedDoors),
|
||||
x => x.Standable(refT.Map),
|
||||
x => true,
|
||||
out IntVec3 result
|
||||
)
|
||||
)
|
||||
FilthMaker.TryMakeFilth(result, refT.Map, filthDef);
|
||||
}
|
||||
|
||||
public static void ThrowCustomSmoke(ThingDef moteDef, Vector3 loc, Map map, float size)
|
||||
{
|
||||
if (loc.ShouldSpawnMotesAt(map) && !map.moteCounter.SaturatedLowPriority)
|
||||
{
|
||||
MoteThrown obj = (MoteThrown)ThingMaker.MakeThing(moteDef);
|
||||
obj.Scale = Rand.Range(1.5f, 2.5f) * size;
|
||||
obj.rotationRate = Rand.Range(-30f, 30f);
|
||||
obj.exactPosition = loc;
|
||||
obj.SetVelocity(Rand.Range(30, 40), Rand.Range(0.5f, 0.7f));
|
||||
GenSpawn.Spawn(obj, loc.ToIntVec3(), map);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryDoSpawn(
|
||||
Pawn pawn,
|
||||
ThingDef thingDef,
|
||||
int thingNum,
|
||||
int spawnMaxAdjacent,
|
||||
bool tryToUnstack,
|
||||
bool inheritFaction,
|
||||
bool spawnForbidden,
|
||||
bool showMessageIfOwned
|
||||
)
|
||||
{
|
||||
Thing refThing = ThingInCaseOfDeath(pawn);
|
||||
IntVec3 spawnPos;
|
||||
Map map;
|
||||
if (refThing == null)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
map = refThing.Map;
|
||||
spawnPos = refThing.Position;
|
||||
}
|
||||
|
||||
if (spawnMaxAdjacent >= 0)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
IntVec3 c = spawnPos + GenAdj.AdjacentCellsAndInside[i];
|
||||
if (!c.InBounds(map))
|
||||
continue;
|
||||
|
||||
List<Thing> thingList = c.GetThingList(map);
|
||||
|
||||
for (int j = 0; j < thingList.Count; j++)
|
||||
{
|
||||
if (thingList[j].def == thingDef)
|
||||
{
|
||||
if (tryToUnstack)
|
||||
continue;
|
||||
|
||||
num += thingList[j].stackCount;
|
||||
if (num >= spawnMaxAdjacent)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TryFindSpawnCell(refThing, thingDef, thingNum, tryToUnstack, out IntVec3 result))
|
||||
{
|
||||
Thing thing = ThingMaker.MakeThing(thingDef);
|
||||
thing.stackCount = thingNum;
|
||||
if (thing == null)
|
||||
Log.Error("Could not spawn anything for " + refThing);
|
||||
|
||||
if (inheritFaction && thing.Faction != refThing.Faction)
|
||||
thing.SetFaction(refThing.Faction);
|
||||
|
||||
GenPlace.TryPlaceThing(
|
||||
thing,
|
||||
result,
|
||||
map,
|
||||
ThingPlaceMode.Direct,
|
||||
out Thing lastResultingThing
|
||||
);
|
||||
if (spawnForbidden)
|
||||
lastResultingThing.SetForbidden(value: true);
|
||||
|
||||
if (showMessageIfOwned && refThing.Faction == Faction.OfPlayer)
|
||||
Messages.Message(
|
||||
"MessageCompSpawnerSpawnedItem".Translate(thingDef.LabelCap),
|
||||
thing,
|
||||
MessageTypeDefOf.PositiveEvent
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryFindSpawnCell(
|
||||
Thing parent,
|
||||
ThingDef thingToSpawn,
|
||||
int spawnCount,
|
||||
bool tryToUnstack,
|
||||
out IntVec3 result
|
||||
)
|
||||
{
|
||||
foreach (IntVec3 item in GenAdj.CellsAdjacent8Way(parent).InRandomOrder())
|
||||
{
|
||||
if (item.Walkable(parent.Map))
|
||||
{
|
||||
Building edifice = item.GetEdifice(parent.Map);
|
||||
if (edifice == null || !thingToSpawn.IsEdifice())
|
||||
{
|
||||
Building_Door building_Door = edifice as Building_Door;
|
||||
if (
|
||||
(building_Door == null || building_Door.FreePassage)
|
||||
&& (
|
||||
parent.def.passability == Traversability.Impassable
|
||||
|| GenSight.LineOfSight(parent.Position, item, parent.Map)
|
||||
)
|
||||
)
|
||||
{
|
||||
bool flag = false;
|
||||
List<Thing> thingList = item.GetThingList(parent.Map);
|
||||
|
||||
for (int i = 0; i < thingList.Count; i++)
|
||||
{
|
||||
Thing thing = thingList[i];
|
||||
if (
|
||||
thing.def.category == ThingCategory.Item
|
||||
&& (
|
||||
thing.def != thingToSpawn
|
||||
|| thing.stackCount > thingToSpawn.stackLimit - spawnCount
|
||||
)
|
||||
)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
result = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = IntVec3.Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool RemoveBadMemoriesOfDeadPawn(Pawn deadPawn, bool myDebug = false)
|
||||
{
|
||||
bool didIt = false;
|
||||
if (deadPawn == null)
|
||||
{
|
||||
Log.Warning("removingRelationAndThoughts, null pawn");
|
||||
return didIt;
|
||||
}
|
||||
string deadName = deadPawn.LabelShortCap;
|
||||
Log.Warning(">>>>>" + deadName + " dissappeared, the world must not know");
|
||||
|
||||
foreach (
|
||||
Pawn p in Find.CurrentMap.mapPawns.AllPawnsSpawned.Where(pH =>
|
||||
pH != deadPawn
|
||||
&& pH.needs.mood?.thoughts?.memories != null
|
||||
&& pH.needs.mood.thoughts.memories.AnyMemoryConcerns(deadPawn)
|
||||
)
|
||||
)
|
||||
{
|
||||
Log.Warning(p.LabelShortCap + " has memories of " + deadName);
|
||||
|
||||
Log.Warning(
|
||||
"pre removal mem count: " + p.needs.mood.thoughts.memories.Memories.Count
|
||||
);
|
||||
p.needs.mood.thoughts.memories.Memories.RemoveAll(TM =>
|
||||
TM.otherPawn == deadPawn && TM.MoodOffset() <= 0f
|
||||
);
|
||||
Log.Warning(
|
||||
"post removal mem count: " + p.needs.mood.thoughts.memories.Memories.Count
|
||||
);
|
||||
}
|
||||
|
||||
return didIt;
|
||||
}
|
||||
|
||||
public static void removingRelationAndThoughts(Pawn deadPawn, bool myDebug = false)
|
||||
{
|
||||
if (deadPawn == null)
|
||||
{
|
||||
Log.Warning("removingRelationAndThoughts, null pawn");
|
||||
return;
|
||||
}
|
||||
string deadName = deadPawn.LabelShortCap;
|
||||
|
||||
Log.Warning(">>>>>" + deadName + " dissappeared, the world must not know");
|
||||
foreach (
|
||||
Pawn p in Find.CurrentMap.mapPawns.AllPawnsSpawned.Where(pH =>
|
||||
//!pH.AnimalOrWildMan() &&
|
||||
pH != deadPawn
|
||||
&& !pH.GetRelations(deadPawn).EnumerableNullOrEmpty()
|
||||
)
|
||||
)
|
||||
{
|
||||
string pName = p.LabelShortCap;
|
||||
Log.Warning("Considering :" + pName);
|
||||
IEnumerable<PawnRelationDef> relationT = PawnRelationUtility.GetRelations(
|
||||
deadPawn,
|
||||
p
|
||||
);
|
||||
if (relationT.EnumerableNullOrEmpty())
|
||||
continue;
|
||||
|
||||
List<Thought> pThoughts = new List<Thought>();
|
||||
if (p.needs.mood == null || p.needs.mood.thoughts == null)
|
||||
continue;
|
||||
//p.needs.mood.thoughts.memories.AnyMemoryConcerns()
|
||||
if (pThoughts.NullOrEmpty())
|
||||
return;
|
||||
int tNum = 0;
|
||||
foreach (Thought thought in pThoughts)
|
||||
{
|
||||
Log.Warning(pName + "'s Thought n" + tNum);
|
||||
tNum++;
|
||||
|
||||
if (thought.pawn == null || deadPawn == null)
|
||||
continue;
|
||||
|
||||
if (IsDeathThought(thought.def))
|
||||
{
|
||||
if (
|
||||
!(
|
||||
thought is Thought_MemorySocial TMS
|
||||
&& TMS.otherPawn != null
|
||||
&& TMS.otherPawn == deadPawn
|
||||
)
|
||||
)
|
||||
continue;
|
||||
|
||||
deadPawn.needs.mood.thoughts.memories.RemoveMemory(TMS);
|
||||
|
||||
Log.Warning(
|
||||
"removed " + pName + "'s thought " + thought.def.defName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.Warning("<<<<<" + deadName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user