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

Binary file not shown.

View File

@@ -322,8 +322,8 @@
<AbilityDef>
<defName>ARA_Ability_Smokepop</defName>
<label>浓雾腔室释放</label>
<description>浓雾种将其腹部的大量白色压缩气体和阻燃泡沫一股脑喷射到空中,形成一大片足以遮蔽虫族身形的烟雾,并防止敌方使用火焰武器点燃虫族集群。</description>
<label>信息素浓雾释放</label>
<description>浓雾种将其腹部的大量释放阿拉克涅信息素烟雾,吸引附近的阿拉克涅辅虫破土而出支援虫群。形成一大片足以遮蔽虫族身形的烟雾,并防止敌方使用火焰武器点燃虫族集群。</description>
<iconPath>UI/Abilities/MechSmokepop</iconPath>
<cooldownTicksRange>6000</cooldownTicksRange>
<targetRequired>false</targetRequired>
@@ -344,15 +344,22 @@
<needCost>0.25</needCost>
<failMessage>营养值不足,需要进食</failMessage>
</li>
<li Class="CompProperties_AbilityFirefoampop">
<!--<li Class="CompProperties_AbilityFirefoampop">
<firefoamRadius>10</firefoamRadius>
<clamorType>Ability</clamorType>
<clamorRadius>15</clamorRadius>
</li>
<li Class="CompProperties_AbilitySmokepop">
</li>-->
<li Class="ArachnaeSwarm.CompProperties_AbilityDRM_Deaddustpop">
<damageDef>ARA_ReinforceGas</damageDef>
<damageAmount>5</damageAmount>
<armorPenetration>2.0</armorPenetration>
<smokeRadius>10</smokeRadius>
<explosionSound>Explosion_Smoke</explosionSound>
<clamorType>Ability</clamorType>
<clamorRadius>15</clamorRadius>
<postExplosionSpawnThingDef>ARA_ReinforceGasCloud</postExplosionSpawnThingDef> <!-- ARL_ToxicGasCloud -->
<postExplosionSpawnChance>1</postExplosionSpawnChance>
<postExplosionSpawnThingCount>1</postExplosionSpawnThingCount>
</li>
<!-- <li Class="ArachnaeSwarm.CompProperties_AbilityBodyPartCheck">
<requiredPart>ARA_Toxic_Needle</requiredPart>
@@ -451,4 +458,5 @@
</li>
</comps>
</ThingDef>
</Defs>

View File

@@ -54,4 +54,17 @@
</additionalHediffsThisPart>
</DamageDef>
<DamageDef ParentName="Flame">
<defName>ARA_ReinforceGas</defName>
<label>信息素烟雾</label>
<workerClass>DamageWorker_AddInjury</workerClass>
<soundExplosion>Explosion_Smoke</soundExplosion>
<combatLogRules>Damage_Smoke</combatLogRules>
<additionalHediffs>
<li>
<hediff>ARA_ReinforceGasCoverd</hediff>
</li>
</additionalHediffs>
</DamageDef>
</Defs>

View File

@@ -96,10 +96,14 @@
<comps>
<li Class="HediffCompProperties_Disappears">
<disappearsAfterTicks>600</disappearsAfterTicks>
<showRemainingTime>True</showRemainingTime>
</li>
<li Class="HediffCompProperties_DisappearsOnDeath"/>
<li Class="ArachnaeSwarm.HediffCompProperties_SpawnPawnOnRemoved">
<pawnKindDef>ArachnaeBase_Race_Skyhive</pawnKindDef>
<pawnKindDefs>
<li>ArachnaeBase_Race_Skyhive</li>
</pawnKindDefs>
<spawnCount>1</spawnCount>
<fixedBiologicalAge>0</fixedBiologicalAge>
</li>
</comps>
@@ -133,7 +137,7 @@
</dataNorth>
<dataEast>
<rotationOffset>245</rotationOffset>
<offset>(0.05, 0, 0.02)</offset>
<offset>(0.05, 0, 0.02)</offset>
</dataEast>
<dataSouth>
<rotationOffset>2</rotationOffset>
@@ -148,4 +152,50 @@
</li>
</renderNodeProperties>
</HediffDef>
<HediffDef>
<defName>ARA_ReinforceGasCoverd</defName>
<label>阿拉克涅信息素沾染</label>
<description>你身上沾染了阿拉克涅信息素,一只阿拉克涅虫族正向你而来。</description>
<!--<tendable>false</tendable> Must be removed via surgery -->
<!--<displayWound>true</displayWound>-->
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<comps>
<li Class="HediffCompProperties_Disappears">
<disappearsAfterTicks>1200</disappearsAfterTicks>
<showRemainingTime>True</showRemainingTime>
</li>
<li Class="HediffCompProperties_DisappearsOnDeath"/>
<li Class="ArachnaeSwarm.HediffCompProperties_SpawnPawnOnRemoved">
<pawnKindDefs>
<li>ArachnaeBase_Race_Acid</li>
</pawnKindDefs>
<spawnCount>1</spawnCount>
<fixedBiologicalAge>0</fixedBiologicalAge>
</li>
</comps>
</HediffDef>
<HediffDef>
<defName>ARA_Unburnable</defName>
<label>阻燃烟雾</label>
<description>不会着火.</description>
<hediffClass>HediffWithComps</hediffClass>
<stages>
<li>
<statFactors>
<Flammability>0</Flammability>
</statFactors>
</li>
</stages>
<comps>
<li Class="HediffCompProperties_Disappears">
<disappearsAfterTicks>1200</disappearsAfterTicks>
<showRemainingTime>True</showRemainingTime>
</li>
<li Class="HediffCompProperties_DisappearsOnDeath"/>
</comps>
</HediffDef>
</Defs>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<Defs>
<ThingDef Name="ARA_BaseGas" Abstract="True">
<thingClass>Gas</thingClass>
<label>gas</label>
<category>Gas</category>
<altitudeLayer>Gas</altitudeLayer>
<useHitPoints>false</useHitPoints>
<tickerType>Normal</tickerType>
<graphicData>
<graphicClass>Graphic_Gas</graphicClass>
<shaderType>Transparent</shaderType>
</graphicData>
</ThingDef>
<!-- Gas : Thing -->
<ThingDef ParentName="ARA_BaseGas">
<defName>ARA_ReinforceGasCloud</defName>
<label>阿拉克涅信息素烟雾</label>
<graphicData>
<texPath>Things/Gas/Puff</texPath>
<drawSize>2.6</drawSize>
<color>(1.0, 0.647, 0.0, 0.5)</color>
</graphicData>
<gas>
<expireSeconds>
<min>15</min>
<max>20</max>
</expireSeconds>
<rotationSpeed>20</rotationSpeed>
</gas>
<thingClass>ArachnaeSwarm.OPToxicGas</thingClass>
<modExtensions>
<li Class="ArachnaeSwarm.OPToxicDefs">
<OPToxicHediff>ARA_Unburnable</OPToxicHediff>
<OPToxicSeverity>0.1</OPToxicSeverity>
<OPSevUpTickPeriod>240</OPSevUpTickPeriod>
</li>
</modExtensions>
</ThingDef>
</Defs>

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;
}
}
}