This commit is contained in:
2025-08-20 16:11:55 +08:00
parent a6ef4e234e
commit 6c1aba4082
7 changed files with 188 additions and 70 deletions

View File

@@ -40,15 +40,18 @@
</costList> </costList>
<verbs> <verbs>
<li> <li>
<verbClass>Verb_Shoot</verbClass> <verbClass>WulaFallenEmpire.Verb_ShootShotgun</verbClass>
<hasStandardCommand>true</hasStandardCommand> <hasStandardCommand>true</hasStandardCommand>
<defaultProjectile>Bullet_ExampleHoming</defaultProjectile> <defaultProjectile>Bullet_ExampleHoming</defaultProjectile>
<warmupTime>1.0</warmupTime> <warmupTime>2.0</warmupTime>
<range>35</range> <range>28</range>
<burstShotCount>1</burstShotCount> <burstShotCount>3</burstShotCount>
<soundCast>Shot_ChargeRifle</soundCast> <!-- Placeholder, needs a proper sound --> <ticksBetweenBurstShots>12</ticksBetweenBurstShots>
<soundCast>Shot_BeamRepeater</soundCast>
<soundCastTail>GunTail_Medium</soundCastTail> <soundCastTail>GunTail_Medium</soundCastTail>
<muzzleFlashScale>9</muzzleFlashScale> <muzzleFlashScale>9</muzzleFlashScale>
<aimingChargeMote>Mote_BeamRepeater_Charge</aimingChargeMote>
<aimingChargeMoteOffset>1.07</aimingChargeMoteOffset>
</li> </li>
</verbs> </verbs>
<weaponTags> <weaponTags>
@@ -64,7 +67,7 @@
<defName>Bullet_ExampleHoming</defName> <defName>Bullet_ExampleHoming</defName>
<label>homing bullet</label> <label>homing bullet</label>
<graphicData> <graphicData>
<texPath>Things/Projectile/Bullet_Big</texPath> <!-- Placeholder, needs a proper texture path --> <texPath>Things/Projectile/Charge_Small</texPath>
<graphicClass>Graphic_Single</graphicClass> <graphicClass>Graphic_Single</graphicClass>
</graphicData> </graphicData>
<thingClass>WulaFallenEmpire.Projectile_TrackingBullet</thingClass> <thingClass>WulaFallenEmpire.Projectile_TrackingBullet</thingClass>
@@ -77,7 +80,7 @@
</projectile> </projectile>
<modExtensions> <modExtensions>
<li Class="WulaFallenEmpire.TrackingBulletDef"> <li Class="WulaFallenEmpire.TrackingBulletDef">
<homingSpeed>0.5</homingSpeed> <homingSpeed>0.1</homingSpeed>
<initRotateAngle>30</initRotateAngle> <initRotateAngle>30</initRotateAngle>
<destroyTicksAfterLosingTrack> <destroyTicksAfterLosingTrack>
<min>60</min> <min>60</min>
@@ -85,6 +88,9 @@
</destroyTicksAfterLosingTrack> </destroyTicksAfterLosingTrack>
<tailFleckDef>WULA_GunTail_Blue</tailFleckDef> <tailFleckDef>WULA_GunTail_Blue</tailFleckDef>
</li> </li>
<li Class="WulaFallenEmpire.ShotgunExtension">
<pelletCount>3</pelletCount>
</li>
</modExtensions> </modExtensions>
</ThingDef> </ThingDef>
</Defs> </Defs>

View File

@@ -65,41 +65,31 @@
<defName>Bullet_ExampleHomingExplosive</defName> <defName>Bullet_ExampleHomingExplosive</defName>
<label>homing explosive bullet</label> <label>homing explosive bullet</label>
<graphicData> <graphicData>
<texPath>Things/Projectile/Bullet_Big</texPath> <!-- Placeholder, needs a proper texture path --> <texPath>Things/Projectile/Charge_Small</texPath>
<graphicClass>Graphic_Single</graphicClass> <graphicClass>Graphic_Single</graphicClass>
</graphicData> </graphicData>
<thingClass>WulaFallenEmpire.Projectile_TrackingBullet</thingClass> <thingClass>WulaFallenEmpire.Projectile_ExplosiveTrackingBullet</thingClass>
<projectile> <projectile>
<speed>25</speed> <speed>60</speed>
<damageDef>Bomb</damageDef> <damageDef>Bomb</damageDef>
<damageAmountBase>30</damageAmountBase> <damageAmountBase>30</damageAmountBase>
<armorPenetrationBase>0.7</armorPenetrationBase> <armorPenetrationBase>0.7</armorPenetrationBase>
<stoppingPower>2.0</stoppingPower> <stoppingPower>2.0</stoppingPower>
<explosionRadius>3.0</explosionRadius>
<explosionDelay>60</explosionDelay>
<screenShakeFactor>1.0</screenShakeFactor>
<applyDamageToExplosionCellsNeighbors>true</applyDamageToExplosionCellsNeighbors>
<preExplosionSpawnChance>1.0</preExplosionSpawnChance>
<preExplosionSpawnThingCount>5</preExplosionSpawnThingCount>
<explosionChanceToStartFire>0.5</explosionChanceToStartFire>
<explosionDamageFalloff>true</explosionDamageFalloff>
<doExplosionVFX>true</doExplosionVFX>
</projectile> </projectile>
<modExtensions> <modExtensions>
<li Class="WulaFallenEmpire.ExplosiveTrackingBulletDef">
<explosionRadius>3.0</explosionRadius>
<damageDef>Bomb</damageDef>
</li>
<li Class="WulaFallenEmpire.TrackingBulletDef"> <li Class="WulaFallenEmpire.TrackingBulletDef">
<homingSpeed>0.5</homingSpeed> <homingSpeed>0.1</homingSpeed>
<initRotateAngle>5</initRotateAngle> <initRotateAngle>15</initRotateAngle>
<destroyTicksAfterLosingTrack> <destroyTicksAfterLosingTrack>
<min>60</min> <min>60</min>
<max>120</max> <max>120</max>
</destroyTicksAfterLosingTrack> </destroyTicksAfterLosingTrack>
<tailFleckDef>Mote_BlastFlame</tailFleckDef> <tailFleckDef>WULA_GunTail_Blue</tailFleckDef>
<fleckMakeFleckTickMax>3</fleckMakeFleckTickMax> <impactThreshold>1</impactThreshold>
<fleckMakeFleckNum>1</fleckMakeFleckNum>
<fleckAngle>30</fleckAngle>
<fleckScale>0.8~1.2</fleckScale>
<fleckSpeed>0.2~0.5</fleckSpeed>
<fleckRotation>0~360</fleckRotation>
</li> </li>
</modExtensions> </modExtensions>
</ThingDef> </ThingDef>

View File

@@ -14,6 +14,11 @@ namespace WulaFallenEmpire
public float postExplosionSpawnChance = 0f; public float postExplosionSpawnChance = 0f;
public int postExplosionSpawnThingCount = 1; public int postExplosionSpawnThingCount = 1;
public GasType? gasType; // 修改为可空类型 public GasType? gasType; // 修改为可空类型
public ThingDef postExplosionSpawnThingDefWater; // 新增
public ThingDef preExplosionSpawnThingDef; // 新增
public float preExplosionSpawnChance = 0f; // 新增
public int preExplosionSpawnThingCount = 0; // 新增
public float screenShakeFactor = 1f; // 新增
public bool applyDamageToExplosionCellsNeighbors = false; public bool applyDamageToExplosionCellsNeighbors = false;
public bool doExplosionDamageAfterThingDestroyed = false; public bool doExplosionDamageAfterThingDestroyed = false;
public float preExplosionSpawnMinMeleeThreat = -1f; public float preExplosionSpawnMinMeleeThreat = -1f;

View File

@@ -8,6 +8,7 @@ namespace WulaFallenEmpire
public class Projectile_ExplosiveTrackingBullet : Projectile_TrackingBullet public class Projectile_ExplosiveTrackingBullet : Projectile_TrackingBullet
{ {
private ExplosiveTrackingBulletDef explosiveDefInt; private ExplosiveTrackingBulletDef explosiveDefInt;
private int ticksToDetonation;
public ExplosiveTrackingBulletDef ExplosiveDef public ExplosiveTrackingBulletDef ExplosiveDef
{ {
@@ -26,52 +27,156 @@ namespace WulaFallenEmpire
} }
} }
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref this.ticksToDetonation, "ticksToDetonation", 0, false);
}
protected override void Tick()
{
base.Tick(); // Call base Projectile_TrackingBullet Tick logic
bool flag = this.ticksToDetonation > 0;
if (flag)
{
this.ticksToDetonation--;
bool flag2 = this.ticksToDetonation <= 0;
if (flag2)
{
this.Explode();
}
}
}
protected override void Impact(Thing hitThing, bool blockedByShield = false) protected override void Impact(Thing hitThing, bool blockedByShield = false)
{ {
base.Impact(hitThing, blockedByShield); // 调用基类的Impact逻辑 bool flag = blockedByShield || ExplosiveDef.explosionDelay == 0; // Use ExplosiveDef for explosionDelay
if (flag)
if (ExplosiveDef.explosionRadius > 0f)
{ {
// 爆炸逻辑 this.Explode();
}
else
{
this.landed = true;
this.ticksToDetonation = ExplosiveDef.explosionDelay; // Use ExplosiveDef for explosionDelay
GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(this, ExplosiveDef.damageDef ?? DamageDefOf.Bomb, this.launcher.Faction, this.launcher); // Use ExplosiveDef for damageDef
}
}
protected virtual void Explode()
{
Map map = base.Map;
// ModExtension_Cone modExtension = this.def.GetModExtension<ModExtension_Cone>(); // Not used in this explosive logic
this.DoExplosion(map); // Call the helper DoExplosion with map
// Cone explosion logic (if needed, based on ModExtension_Cone) - Currently not implemented for this class
// bool flag = modExtension != null;
// if (flag)
// {
// ProjectileProperties projectile = this.def.projectile;
// ModExtension_Cone modExtension_Cone = modExtension;
// IntVec3 position = base.Position;
// Map map2 = map;
// Quaternion exactRotation = this.ExactRotation;
// DamageDef damageDef = projectile.damageDef;
// Thing launcher = base.Launcher;
// int damageAmount = this.DamageAmount;
// float armorPenetration = this.ArmorPenetration;
// SoundDef soundExplode = this.def.projectile.soundExplode;
// ThingDef equipmentDef = this.equipmentDef;
// ThingDef def = this.def;
// Thing thing = this.intendedTarget.Thing;
// ThingDef postExplosionSpawnThingDef = null;
// float postExplosionSpawnChance = 0f;
// int postExplosionSpawnThingCount = 1;
// float screenShakeFactor = this.def.projectile.screenShakeFactor;
// modExtension_Cone.DoConeExplosion(position, map2, exactRotation, damageDef, launcher, damageAmount, armorPenetration, soundExplode, equipmentDef, def, thing, postExplosionSpawnThingDef, postExplosionSpawnChance, postExplosionSpawnThingCount, null, null, 255, false, null, 0f, 1, 0f, false, null, null, 1f, 0f, null, screenShakeFactor, null, null);
// }
// Explosion effect (if needed, based on def.projectile.explosionEffect) - Currently not implemented for this class
// bool flag2 = this.def.projectile.explosionEffect != null;
// if (flag2)
// {
// Effecter effecter = this.def.projectile.explosionEffect.Spawn();
// bool flag3 = this.def.projectile.explosionEffectLifetimeTicks != 0;
// if (flag3)
// {
// map.effecterMaintainer.AddEffecterToMaintain(effecter, base.Position.ToVector3().ToIntVec3(), this.def.projectile.explosionEffectLifetimeTicks);
// }
// else
// {
// effecter.Trigger(new TargetInfo(base.Position, map, false), new TargetInfo(base.Position, map, false), -1);
// effecter.Cleanup();
// }
// }
this.Destroy(DestroyMode.Vanish);
}
protected void DoExplosion(Map map)
{
IntVec3 position = base.Position;
float explosionRadius = ExplosiveDef.explosionRadius; // Use ExplosiveDef for explosionRadius
DamageDef damageDef = ExplosiveDef.damageDef ?? DamageDefOf.Bomb; // Use ExplosiveDef for damageDef
Thing launcher = this.launcher;
int damageAmount = this.DamageAmount;
float armorPenetration = this.ArmorPenetration;
SoundDef soundExplode = ExplosiveDef.soundExplode; // Use ExplosiveDef for soundExplode
ThingDef equipmentDef = this.equipmentDef;
ThingDef def = this.def; // This is the projectile's ThingDef
Thing thing = this.intendedTarget.Thing;
ThingDef postExplosionSpawnThingDef = ExplosiveDef.postExplosionSpawnThingDef; // Use ExplosiveDef for postExplosionSpawnThingDef
ThingDef postExplosionSpawnThingDefWater = ExplosiveDef.postExplosionSpawnThingDefWater; // Use ExplosiveDef for postExplosionSpawnThingDefWater
float postExplosionSpawnChance = ExplosiveDef.postExplosionSpawnChance; // Use ExplosiveDef for postExplosionSpawnChance
int postExplosionSpawnThingCount = ExplosiveDef.postExplosionSpawnThingCount; // Use ExplosiveDef for postExplosionSpawnThingCount
GasType? postExplosionGasType = ExplosiveDef.gasType; // Use ExplosiveDef for gasType
ThingDef preExplosionSpawnThingDef = ExplosiveDef.preExplosionSpawnThingDef; // Use ExplosiveDef for preExplosionSpawnThingDef
float preExplosionSpawnChance = ExplosiveDef.preExplosionSpawnChance; // Use ExplosiveDef for preExplosionSpawnChance
int preExplosionSpawnThingCount = ExplosiveDef.preExplosionSpawnThingCount; // Use ExplosiveDef for preExplosionSpawnThingCount
bool applyDamageToExplosionCellsNeighbors = ExplosiveDef.applyDamageToExplosionCellsNeighbors; // Use ExplosiveDef for applyDamageToExplosionCellsNeighbors
float explosionChanceToStartFire = ExplosiveDef.explosionChanceToStartFire; // Use ExplosiveDef for explosionChanceToStartFire
bool explosionDamageFalloff = ExplosiveDef.explosionDamageFalloff; // Use ExplosiveDef for explosionDamageFalloff
float? direction = new float?(this.origin.AngleToFlat(this.destination)); // This remains from original logic
float screenShakeFactor = ExplosiveDef.screenShakeFactor; // Use ExplosiveDef for screenShakeFactor
bool doExplosionVFX = ExplosiveDef.doExplosionVFX; // Use ExplosiveDef for doExplosionVFX
GenExplosion.DoExplosion( GenExplosion.DoExplosion(
center: Position, // 爆炸中心 center: position, // 爆炸中心
map: Map, // 地图 map: map, // 地图
radius: ExplosiveDef.explosionRadius, // 爆炸半径 radius: explosionRadius, // 爆炸半径
damType: ExplosiveDef.damageDef ?? DamageDefOf.Bomb, // 伤害类型如果未配置则默认为Bomb damType: damageDef, // 伤害类型
instigator: launcher, // 制造者 instigator: launcher, // 制造者
damAmount: this.DamageAmount, // 伤害量,使用子弹当前的伤害量 damAmount: damageAmount, // 伤害量
armorPenetration: this.ArmorPenetration, // 护甲穿透,使用子弹当前的护甲穿透 armorPenetration: armorPenetration, // 护甲穿透
explosionSound: ExplosiveDef.soundExplode, // 爆炸音效 explosionSound: soundExplode, // 爆炸音效
weapon: equipmentDef, // 武器 weapon: equipmentDef, // 武器
projectile: def, // 弹药定义 projectile: def, // 弹药定义
intendedTarget: intendedTarget.Thing, // 预期目标 intendedTarget: thing, // 预期目标
postExplosionSpawnThingDef: ExplosiveDef.postExplosionSpawnThingDef, // 爆炸后生成物 postExplosionSpawnThingDef: postExplosionSpawnThingDef, // 爆炸后生成物
postExplosionSpawnChance: ExplosiveDef.postExplosionSpawnChance, // 爆炸后生成几率 postExplosionSpawnChance: postExplosionSpawnChance, // 爆炸后生成几率
postExplosionSpawnThingCount: ExplosiveDef.postExplosionSpawnThingCount, // 爆炸后生成数量 postExplosionSpawnThingCount: postExplosionSpawnThingCount, // 爆炸后生成数量
postExplosionGasType: ExplosiveDef.gasType, // 气体类型 (注意参数名已修正) postExplosionGasType: postExplosionGasType, // 气体类型
postExplosionGasRadiusOverride: null, // 爆炸气体半径覆盖 (我没有定义这个参数) postExplosionGasRadiusOverride: null, // 爆炸气体半径覆盖
postExplosionGasAmount: 255, // 爆炸气体数量 (默认值) postExplosionGasAmount: 255, // 爆炸气体数量
applyDamageToExplosionCellsNeighbors: ExplosiveDef.applyDamageToExplosionCellsNeighbors, // 是否对爆炸单元格邻居造成伤害 applyDamageToExplosionCellsNeighbors: applyDamageToExplosionCellsNeighbors, // 是否对爆炸单元格邻居造成伤害
preExplosionSpawnThingDef: null, // 爆炸前生成物 (我没有定义这个参数) preExplosionSpawnThingDef: preExplosionSpawnThingDef, // 爆炸前生成物
preExplosionSpawnChance: 0f, // 爆炸前生成几率 (默认值) preExplosionSpawnChance: preExplosionSpawnChance, // 爆炸前生成几率
preExplosionSpawnThingCount: 0, // 爆炸前生成数量 (默认值) preExplosionSpawnThingCount: preExplosionSpawnThingCount, // 爆炸前生成数量
chanceToStartFire: ExplosiveDef.explosionChanceToStartFire, // 是否有几率点燃 (注意参数名已修正) chanceToStartFire: explosionChanceToStartFire, // 是否有几率点燃
damageFalloff: ExplosiveDef.explosionDamageFalloff, // 爆炸伤害衰减 damageFalloff: explosionDamageFalloff, // 爆炸伤害衰减
direction: null, // 方向 (我没有定义这个参数) direction: direction, // 方向
ignoredThings: null, // 忽略的物体 (我没有定义这个参数) ignoredThings: null, // 忽略的物体
affectedAngle: null, // 受影响角度 (我没有定义这个参数) affectedAngle: null, // 受影响角度
doVisualEffects: ExplosiveDef.doExplosionVFX, // 是否显示视觉效果 doVisualEffects: doExplosionVFX, // 是否显示视觉效果
propagationSpeed: 1f, // 传播速度 (默认值) propagationSpeed: 1f, // 传播速度
excludeRadius: 0f, // 排除半径 (默认值) excludeRadius: 0f, // 排除半径
doSoundEffects: true, // 是否播放音效 (默认值) doSoundEffects: true, // 是否播放音效
postExplosionSpawnThingDefWater: null, // 爆炸后在水中生成物 (我没有定义这个参数) postExplosionSpawnThingDefWater: postExplosionSpawnThingDefWater, // 爆炸后在水中生成物
screenShakeFactor: 1f, // 屏幕震动因子 (默认值) screenShakeFactor: screenShakeFactor, // 屏幕震动因子
flammabilityChanceCurve: null, // 易燃性几率曲线 (我没有定义这个参数) flammabilityChanceCurve: null, // 易燃性几率曲线
overrideCells: null, // 覆盖单元格 (我没有定义这个参数) overrideCells: null, // 覆盖单元格
postExplosionSpawnSingleThingDef: null, // 爆炸后生成单个物体 (我没有定义这个参数) postExplosionSpawnSingleThingDef: null, // 爆炸后生成单个物体
preExplosionSpawnSingleThingDef: null // 爆炸前生成单个物体 (我没有定义这个参数) preExplosionSpawnSingleThingDef: null // 爆炸前生成单个物体
); );
} }
} }
}
} }

View File

@@ -196,6 +196,17 @@ namespace WulaFallenEmpire
return; return;
} }
// 在调用 ProjectileCheckForFreeInterceptBetween 之前,添加近距离命中检测
if (intendedTarget != null && intendedTarget.Thing != null && intendedTarget.Thing.Spawned)
{
float distanceToTarget = (ExactPosition - intendedTarget.Thing.DrawPos).magnitude;
if (distanceToTarget <= TrackingDef.impactThreshold)
{
Impact(intendedTarget.Thing); // 强制命中目标
return; // 命中后立即返回,不再执行后续逻辑
}
}
// 检查是否有东西在路径上拦截 // 检查是否有东西在路径上拦截
// ProjectileCheckForFreeInterceptBetween 会在内部处理命中,并调用 ImpactSomething() // ProjectileCheckForFreeInterceptBetween 会在内部处理命中,并调用 ImpactSomething()
// 所以这里不需要额外的 ImpactSomething() 调用 // 所以这里不需要额外的 ImpactSomething() 调用

View File

@@ -6,6 +6,7 @@ namespace WulaFallenEmpire
{ {
public float homingSpeed = 0.1f; // 追踪速度,值越大追踪越灵敏 public float homingSpeed = 0.1f; // 追踪速度,值越大追踪越灵敏
public float initRotateAngle = 0f; // 初始旋转角度 public float initRotateAngle = 0f; // 初始旋转角度
public float impactThreshold = 0.5f; // 强制命中阈值,子弹与目标距离小于此值时强制命中
public FleckDef tailFleckDef; // 拖尾特效的FleckDef public FleckDef tailFleckDef; // 拖尾特效的FleckDef
public int fleckMakeFleckTickMax = 1; // 拖尾特效的生成间隔tick public int fleckMakeFleckTickMax = 1; // 拖尾特效的生成间隔tick