This commit is contained in:
2025-09-09 17:51:20 +08:00
parent 6e9b0829b7
commit de5c7412b3
9 changed files with 426 additions and 24 deletions

View File

@@ -0,0 +1,85 @@
using RimWorld;
using Verse;
using Verse.Sound;
using System.Collections.Generic;
using System.Linq;
namespace ArachnaeSwarm
{
public class CompAbilityEffect_DRM_Deaddustpop : CompAbilityEffect
{
public new CompProperties_AbilityDRM_Deaddustpop Props
{
get
{
return (CompProperties_AbilityDRM_Deaddustpop)this.props;
}
}
private Pawn Pawn
{
get
{
return this.parent.pawn;
}
}
private List<IntVec3> AffectedCells(LocalTargetInfo target)
{
return GenRadial.RadialCellsAround(target.Cell, Props.smokeRadius, true).ToList();
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
GenExplosion.DoExplosion(
center: target.Cell,
map: this.parent.pawn.MapHeld,
radius: this.Props.smokeRadius,
damType: this.Props.damageDef,
instigator: null,
damAmount: this.Props.damageAmount,
armorPenetration: this.Props.armorPenetration,
// 明确命名关键参数,避免顺序错误
postExplosionSpawnThingDef: this.Props.postExplosionSpawnThingDef,
postExplosionSpawnChance: this.Props.postExplosionSpawnChance,
postExplosionSpawnThingCount: this.Props.postExplosionSpawnThingCount,
postExplosionGasType: this.Props.gasType,
// 需要补充的参数(根据实际需求填写)
flammabilityChanceCurve: null,
overrideCells: this.AffectedCells(target), // 明确传递实际需要的值
postExplosionSpawnSingleThingDef: null,
preExplosionSpawnSingleThingDef: null
);
}
public override void DrawEffectPreview(LocalTargetInfo target)
{
GenDraw.DrawRadiusRing(target.Cell, this.Props.smokeRadius);
}
}
public class CompProperties_AbilityDRM_Deaddustpop : CompProperties_AbilityEffect
{
public CompProperties_AbilityDRM_Deaddustpop()
{
this.compClass = typeof(CompAbilityEffect_DRM_Deaddustpop);
}
public float smokeRadius;
public SoundDef explosionSound;
public GasType gasType;
public DamageDef damageDef;
public float postExplosionSpawnChance = 0f;
public int postExplosionSpawnThingCount = 1;
public ThingDef postExplosionSpawnThingDef = null;
public int damageAmount = -1;
public float armorPenetration = -1f;
}
}

View File

@@ -154,6 +154,7 @@
<Compile Include="CompPawnFlight.cs" />
<Compile Include="CompProperties_PawnFlight.cs" />
<Compile Include="HarmonyPatches.cs" />
<Compile Include="OPToxicGas.cs" />
</ItemGroup>
<ItemGroup>
@@ -164,6 +165,7 @@
<Compile Include="Abilities\CompProperties_TrackingCharge.cs" />
<Compile Include="Abilities\PawnFlyer_TrackingCharge.cs" />
<Compile Include="Abilities\Verb_CastAbilityTrackingCharge.cs" />
<Compile Include="Abilities\CompAbilityEffect_DRM_Deaddustpop.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="HediffComp_SpawnPawnOnRemoved.cs" />

View File

@@ -1,5 +1,7 @@
using RimWorld;
using Verse;
using System.Collections.Generic;
using System.Linq;
namespace ArachnaeSwarm
{
@@ -9,7 +11,8 @@ namespace ArachnaeSwarm
/// </summary>
public class HediffCompProperties_SpawnPawnOnRemoved : HediffCompProperties
{
public PawnKindDef pawnKindDef;
public List<PawnKindDef> pawnKindDefs; // 更改为列表
public int spawnCount = 1; // 新增生成数量
public float? fixedBiologicalAge; // 新增用于XML配置的固定生物年龄
public FloatRange? biologicalAgeRange; // 新增用于XML配置的生物年龄范围
@@ -49,32 +52,43 @@ namespace ArachnaeSwarm
{
base.CompPostPostRemoved();
if (this.Pawn == null || this.Pawn.Map == null || Props.pawnKindDef == null)
if (this.Pawn == null || this.Pawn.Map == null || Props.pawnKindDefs.NullOrEmpty())
{
Log.Warning("ArachnaeSwarm: HediffComp_SpawnPawnOnRemoved tried to spawn a pawn but required data was missing (Pawn, Map, or pawnKindDef).");
Log.Warning("ArachnaeSwarm: HediffComp_SpawnPawnOnRemoved tried to spawn a pawn but required data was missing (Pawn, Map, or pawnKindDefs).");
return;
}
Map map = this.Pawn.Map;
IntVec3 loc = this.Pawn.Position;
Pawn newPawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(
kind: Props.pawnKindDef,
faction: this.casterFaction, // Use the stored faction
context: PawnGenerationContext.NonPlayer,
tile: -1,
forceGenerateNewPawn: true,
fixedBiologicalAge: Props.fixedBiologicalAge, // 使用XML配置的固定生物年龄
biologicalAgeRange: Props.biologicalAgeRange // 使用XML配置的生物年龄范围
));
if (newPawn != null)
// If casterFaction is null, default to the player's faction
if (this.casterFaction == null)
{
GenSpawn.Spawn(newPawn, loc, map, WipeMode.Vanish);
this.casterFaction = Faction.OfPlayer;
}
else
for (int i = 0; i < Props.spawnCount; i++)
{
Log.Error($"ArachnaeSwarm: Failed to generate pawn of kind {Props.pawnKindDef.defName}.");
PawnKindDef selectedPawnKindDef = Props.pawnKindDefs.RandomElement();
Pawn newPawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(
kind: selectedPawnKindDef,
faction: this.casterFaction, // Use the stored faction
context: PawnGenerationContext.NonPlayer,
tile: -1,
forceGenerateNewPawn: true,
fixedBiologicalAge: Props.fixedBiologicalAge, // 使用XML配置的固定生物年龄
biologicalAgeRange: Props.biologicalAgeRange // 使用XML配置的生物年龄范围
));
if (newPawn != null)
{
GenSpawn.Spawn(newPawn, loc, map, WipeMode.Vanish);
}
else
{
Log.Error($"ArachnaeSwarm: Failed to generate pawn of kind {selectedPawnKindDef.defName}.");
}
}
}

View File

@@ -0,0 +1,187 @@
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class OPToxicGas : Gas
{
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
base.SpawnSetup(map, true);
this.destroyTick = Find.TickManager.TicksGame + this.def.gas.expireSeconds.RandomInRange.SecondsToTicks();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look<int>(ref this.destroyTick, "destroyTick", 0, false);
}
protected override void Tick()
{
bool flag = this.destroyTick <= Find.TickManager.TicksGame;
if (flag)
{
this.Destroy(DestroyMode.Vanish);
}
this.graphicRotation += this.graphicRotationSpeed;
bool flag2 = !base.Destroyed && Find.TickManager.TicksGame % OPToxicDefGetValue.OPToxicGetSevUpVal(this.def) == 0;
if (flag2)
{
Map map = base.Map;
IntVec3 position = base.Position;
List<Thing> thingList = position.GetThingList(map);
bool flag3 = thingList.Count > 0;
if (flag3)
{
for (int i = 0; i < thingList.Count; i++)
{
bool flag4 = thingList[i] is Pawn && !(thingList[i] as Pawn).RaceProps.IsMechanoid && thingList[i].Position == position;
if (flag4)
{
this.DoOPToxicGas(this, thingList[i]);
}
}
}
}
}
public void DoOPToxicGas(Thing Gas, Thing targ)
{
Pawn pawn = targ as Pawn;
bool flag = pawn != null && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Breathing);
if (flag)
{
HediffDef namedSilentFail = DefDatabase<HediffDef>.GetNamedSilentFail(OPToxicDefGetValue.OPToxicGetHediff(Gas.def));
bool flag2 = namedSilentFail != null;
if (flag2)
{
Pawn_HealthTracker health = pawn.health;
bool flag3 = health == null;
Hediff hediff;
if (flag3)
{
hediff = null;
}
else
{
HediffSet hediffSet = health.hediffSet;
hediff = ((hediffSet != null) ? hediffSet.GetFirstHediffOfDef(namedSilentFail, false) : null);
}
float num = 1f - pawn.GetStatValue(StatDefOf.ToxicResistance, true, -1);
float num2 = OPToxicDefGetValue.OPToxicGetSev(Gas.def);
bool flag4 = num2 < 0.01f;
if (flag4)
{
num2 = 0.01f;
}
float num3 = Rand.Range(0.01f * num, num2 * num);
bool flag5 = hediff != null && num3 > 0f;
if (flag5)
{
hediff.Severity += num3;
}
else
{
Hediff hediff2 = HediffMaker.MakeHediff(namedSilentFail, pawn, null);
hediff2.Severity = num3;
pawn.health.AddHediff(hediff2, null, null, null);
}
}
}
}
}
public class OPToxicDefGetValue
{
public static string OPToxicGetHediff(ThingDef thingdef)
{
bool flag = thingdef.HasModExtension<OPToxicDefs>();
string result;
if (flag)
{
result = thingdef.GetModExtension<OPToxicDefs>().OPToxicHediff;
}
else
{
result = null;
}
return result;
}
public static float OPToxicGetSev(ThingDef thingdef)
{
bool flag = thingdef.HasModExtension<OPToxicDefs>();
float result;
if (flag)
{
result = thingdef.GetModExtension<OPToxicDefs>().OPToxicSeverity;
}
else
{
result = 0f;
}
return result;
}
public static int OPToxicGetSevUpVal(ThingDef thingdef)
{
bool flag = thingdef.HasModExtension<OPToxicDefs>();
int result;
if (flag)
{
result = thingdef.GetModExtension<OPToxicDefs>().OPSevUpTickPeriod;
}
else
{
result = 120;
}
return result;
}
}
public class OPToxicDefs : DefModExtension
{
public string OPToxicHediff;
public float OPToxicSeverity;
public int OPSevUpTickPeriod = 120;
}
public class DamageWorker_OPToxic : DamageWorker
{
public override void ExplosionStart(Explosion explosion, List<IntVec3> cellsToAffect)
{
bool flag = this.def.explosionHeatEnergyPerCell > float.Epsilon;
if (flag)
{
GenTemperature.PushHeat(explosion.Position, explosion.Map, this.def.explosionHeatEnergyPerCell * (float)cellsToAffect.Count);
}
FleckMaker.Static(explosion.Position, explosion.Map, FleckDefOf.ExplosionFlash, explosion.radius * 6f);
FleckMaker.Static(explosion.Position, explosion.Map, FleckDefOf.ExplosionFlash, explosion.radius * 6f);
this.ExplosionVisualEffectCenter(explosion);
}
public override DamageWorker.DamageResult Apply(DamageInfo dinfo, Thing victim)
{
DamageWorker.DamageResult damageResult = new DamageWorker.DamageResult();
bool flag = victim.def.category == ThingCategory.Pawn && victim.def.useHitPoints && dinfo.Def.harmsHealth;
if (flag)
{
float amount = dinfo.Amount;
damageResult.totalDamageDealt = (float)Mathf.Min(victim.HitPoints, GenMath.RoundRandom(amount));
victim.HitPoints -= Mathf.RoundToInt(damageResult.totalDamageDealt);
bool flag2 = victim.HitPoints <= 0;
if (flag2)
{
victim.HitPoints = 0;
victim.Kill(new DamageInfo?(dinfo), null);
}
}
return damageResult;
}
}
}