diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index ef72ddc5..f6ffb914 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml index 3cf0c030..b55c3dd7 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_Homing.xml @@ -69,7 +69,7 @@ WulaFallenEmpire.Projectile_TrackingBullet - 30 + 60 Bullet 15 0.5 @@ -78,7 +78,12 @@
  • 0.5 - 10 + 30 + + 60 + 120 + + WULA_GunTail_Blue
  • diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml index b6c7a27f..0c5ee6cd 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_Weapon_Homing_Examples_Bullet_HomingExplosive.xml @@ -89,7 +89,17 @@
  • 0.5 5 - + + 60 + 120 + + Mote_BlastFlame + 3 + 1 + 30 + 0.8~1.2 + 0.2~0.5 + 0~360
  • diff --git a/Source/WulaFallenEmpire/ExplosiveTrackingBulletDef.cs b/Source/WulaFallenEmpire/ExplosiveTrackingBulletDef.cs new file mode 100644 index 00000000..e98fcc79 --- /dev/null +++ b/Source/WulaFallenEmpire/ExplosiveTrackingBulletDef.cs @@ -0,0 +1,24 @@ +using Verse; +using RimWorld; + +namespace WulaFallenEmpire +{ + public class ExplosiveTrackingBulletDef : DefModExtension + { + public float explosionRadius = 1.9f; + public DamageDef damageDef; + public int explosionDelay = 0; + public SoundDef soundExplode; + public FleckDef preExplosionFlash; + public ThingDef postExplosionSpawnThingDef; + public float postExplosionSpawnChance = 0f; + public int postExplosionSpawnThingCount = 1; + public GasType? gasType; // 修改为可空类型 + public bool applyDamageToExplosionCellsNeighbors = false; + public bool doExplosionDamageAfterThingDestroyed = false; + public float preExplosionSpawnMinMeleeThreat = -1f; + public float explosionChanceToStartFire = 0f; // 从bool改为float,并设置默认值 + public bool explosionDamageFalloff = false; + public bool doExplosionVFX = true; + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs b/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs new file mode 100644 index 00000000..2c407f2e --- /dev/null +++ b/Source/WulaFallenEmpire/Projectile_ExplosiveTrackingBullet.cs @@ -0,0 +1,77 @@ +using RimWorld; +using UnityEngine; +using Verse; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class Projectile_ExplosiveTrackingBullet : Projectile_TrackingBullet + { + private ExplosiveTrackingBulletDef explosiveDefInt; + + public ExplosiveTrackingBulletDef ExplosiveDef + { + get + { + if (explosiveDefInt == null) + { + explosiveDefInt = def.GetModExtension(); + if (explosiveDefInt == null) + { + Log.ErrorOnce($"ExplosiveTrackingBulletDef for {this.def.defName} is null. Creating a default instance.", this.thingIDNumber ^ 0x12345679); + this.explosiveDefInt = new ExplosiveTrackingBulletDef(); + } + } + return explosiveDefInt; + } + } + + protected override void Impact(Thing hitThing, bool blockedByShield = false) + { + base.Impact(hitThing, blockedByShield); // 调用基类的Impact逻辑 + + if (ExplosiveDef.explosionRadius > 0f) + { + // 爆炸逻辑 + GenExplosion.DoExplosion( + center: Position, // 爆炸中心 + map: Map, // 地图 + radius: ExplosiveDef.explosionRadius, // 爆炸半径 + damType: ExplosiveDef.damageDef ?? DamageDefOf.Bomb, // 伤害类型,如果未配置则默认为Bomb + instigator: launcher, // 制造者 + damAmount: this.DamageAmount, // 伤害量,使用子弹当前的伤害量 + armorPenetration: this.ArmorPenetration, // 护甲穿透,使用子弹当前的护甲穿透 + explosionSound: ExplosiveDef.soundExplode, // 爆炸音效 + weapon: equipmentDef, // 武器 + projectile: def, // 弹药定义 + intendedTarget: intendedTarget.Thing, // 预期目标 + postExplosionSpawnThingDef: ExplosiveDef.postExplosionSpawnThingDef, // 爆炸后生成物 + postExplosionSpawnChance: ExplosiveDef.postExplosionSpawnChance, // 爆炸后生成几率 + postExplosionSpawnThingCount: ExplosiveDef.postExplosionSpawnThingCount, // 爆炸后生成数量 + postExplosionGasType: ExplosiveDef.gasType, // 气体类型 (注意参数名已修正) + postExplosionGasRadiusOverride: null, // 爆炸气体半径覆盖 (我没有定义这个参数) + postExplosionGasAmount: 255, // 爆炸气体数量 (默认值) + applyDamageToExplosionCellsNeighbors: ExplosiveDef.applyDamageToExplosionCellsNeighbors, // 是否对爆炸单元格邻居造成伤害 + preExplosionSpawnThingDef: null, // 爆炸前生成物 (我没有定义这个参数) + preExplosionSpawnChance: 0f, // 爆炸前生成几率 (默认值) + preExplosionSpawnThingCount: 0, // 爆炸前生成数量 (默认值) + chanceToStartFire: ExplosiveDef.explosionChanceToStartFire, // 是否有几率点燃 (注意参数名已修正) + damageFalloff: ExplosiveDef.explosionDamageFalloff, // 爆炸伤害衰减 + direction: null, // 方向 (我没有定义这个参数) + ignoredThings: null, // 忽略的物体 (我没有定义这个参数) + affectedAngle: null, // 受影响角度 (我没有定义这个参数) + doVisualEffects: ExplosiveDef.doExplosionVFX, // 是否显示视觉效果 + propagationSpeed: 1f, // 传播速度 (默认值) + excludeRadius: 0f, // 排除半径 (默认值) + doSoundEffects: true, // 是否播放音效 (默认值) + postExplosionSpawnThingDefWater: null, // 爆炸后在水中生成物 (我没有定义这个参数) + screenShakeFactor: 1f, // 屏幕震动因子 (默认值) + flammabilityChanceCurve: null, // 易燃性几率曲线 (我没有定义这个参数) + overrideCells: null, // 覆盖单元格 (我没有定义这个参数) + postExplosionSpawnSingleThingDef: null, // 爆炸后生成单个物体 (我没有定义这个参数) + preExplosionSpawnSingleThingDef: null // 爆炸前生成单个物体 (我没有定义这个参数) + ); + } + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_TrackingBullet.cs b/Source/WulaFallenEmpire/Projectile_TrackingBullet.cs index 4dc05f36..07b1aa2c 100644 --- a/Source/WulaFallenEmpire/Projectile_TrackingBullet.cs +++ b/Source/WulaFallenEmpire/Projectile_TrackingBullet.cs @@ -15,6 +15,9 @@ namespace WulaFallenEmpire protected Vector3 exactPositionInt; public Vector3 curSpeed; public bool homing = true; + private int destroyTicksAfterLosingTrack = -1; // 失去追踪后多少tick自毁,-1表示不自毁 + private int Fleck_MakeFleckTick; // 拖尾特效的计时器 + private Vector3 lastTickPosition; // 记录上一帧的位置,用于计算移动方向 private static class NonPublicFields { @@ -58,6 +61,7 @@ namespace WulaFallenEmpire curSpeed = rotatedDirection * def.projectile.SpeedTilesPerTick; ReflectInit(); + lastTickPosition = origin; // 初始化 lastTickPosition } protected void ReflectInit() @@ -80,67 +84,41 @@ namespace WulaFallenEmpire if (homing) { - // 计算需要转向的方向 - Vector3 desiredDirection = vectorToTarget.normalized; - Vector3 currentDirection = curSpeed.normalized; - - // 计算方向差异 - Vector3 directionDifference = desiredDirection - currentDirection; - - // 如果方向差异过大,可能失去追踪,或者直接转向 - if (directionDifference.sqrMagnitude > 0.001f) // 避免浮点数精度问题 + // 如果目标消失或距离太远,停止追踪 + if (!intendedTarget.IsValid || !intendedTarget.Thing.Spawned || (intendedTarget.Cell.ToVector3() - ExactPosition).magnitude > def.projectile.speed * 2f) // 假设2倍速度为最大追踪距离 { - // 调整当前速度,使其更接近目标方向 - curSpeed += directionDifference * TrackingDef.homingSpeed * curSpeed.magnitude; - curSpeed = curSpeed.normalized * def.projectile.SpeedTilesPerTick; // 保持速度恒定 + homing = false; + destroyTicksAfterLosingTrack = TrackingDef.destroyTicksAfterLosingTrack.RandomInRange; // 失去追踪后根据XML配置的范围自毁 + } + else + { + // 计算需要转向的方向 + Vector3 desiredDirection = vectorToTarget.normalized; + Vector3 currentDirection = curSpeed.normalized; + + // 计算方向差异 + Vector3 directionDifference = desiredDirection - currentDirection; + + // 如果方向差异过大,可能失去追踪,或者直接转向 + if (directionDifference.sqrMagnitude > 0.001f) // 避免浮点数精度问题 + { + // 调整当前速度,使其更接近目标方向 + curSpeed += directionDifference * TrackingDef.homingSpeed * curSpeed.magnitude; + curSpeed = curSpeed.normalized * def.projectile.SpeedTilesPerTick; // 保持速度恒定 + } } } exactPositionInt = ExactPosition + curSpeed; // 更新位置 } - protected override void Tick() - { - base.Tick(); // 调用父类Bullet的Tick,处理一些基本逻辑,如lifetime, ticksToImpact - - MovementTick(); // 调用追踪移动逻辑 - - // 检查是否撞到东西或超出地图 - Vector3 exactPosition = ExactPosition; // 之前的ExactPosition - ticksToImpact--; // 减少impact计时器 - - if (!ExactPosition.InBounds(base.Map)) // 超出地图边界 - { - base.Position = exactPosition.ToIntVec3(); // 设回旧位置,然后销毁 - Destroy(); - return; - } - - // 检查是否有东西在路径上拦截 - Vector3 exactPositionAfterMove = ExactPosition; // 移动后的ExactPosition - object[] parameters = new object[2] { exactPosition, exactPositionAfterMove }; - if (!(bool)NonPublicFields.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters)) - { - base.Position = ExactPosition.ToIntVec3(); // 更新位置到当前精确位置 - if (ticksToImpact <= 0) // 达到impact时间 - { - ImpactSomething(); // 触发Impact - } - } - } - - protected override void Impact(Thing hitThing, bool blockedByShield = false) - { - // 默认Impact逻辑,可以根据需要扩展 - base.Impact(hitThing, blockedByShield); - } - public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref exactPositionInt, "exactPosition"); Scribe_Values.Look(ref curSpeed, "curSpeed"); Scribe_Values.Look(ref homing, "homing", defaultValue: true); + Scribe_Values.Look(ref destroyTicksAfterLosingTrack, "destroyTicksAfterLosingTrack", -1); if (Scribe.mode == LoadSaveMode.PostLoadInit) { ReflectInit(); @@ -155,5 +133,84 @@ namespace WulaFallenEmpire } } } + + protected override void Tick() + { + base.Tick(); // 调用父类Bullet的Tick,处理 ticksToImpact 减少和最终命中 + + if (destroyTicksAfterLosingTrack > 0) + { + destroyTicksAfterLosingTrack--; + if (destroyTicksAfterLosingTrack <= 0) + { + Destroy(); // 如果自毁计时器归零,直接销毁 + return; + } + } + + // 处理拖尾特效 + if (TrackingDef != null && TrackingDef.tailFleckDef != null) + { + Fleck_MakeFleckTick++; + // 只有当达到延迟时间后才开始生成Fleck + if (Fleck_MakeFleckTick >= TrackingDef.fleckDelayTicks) + { + if (Fleck_MakeFleckTick >= (TrackingDef.fleckDelayTicks + TrackingDef.fleckMakeFleckTickMax)) + { + Fleck_MakeFleckTick = TrackingDef.fleckDelayTicks; // 重置计时器,从延迟时间开始循环 + } + + Map map = base.Map; + int randomInRange = TrackingDef.fleckMakeFleckNum.RandomInRange; + Vector3 currentPosition = ExactPosition; + Vector3 previousPosition = lastTickPosition; + + for (int i = 0; i < randomInRange; i++) + { + float num = (currentPosition - previousPosition).AngleFlat(); + float velocityAngle = TrackingDef.fleckAngle.RandomInRange + num; + float randomInRange2 = TrackingDef.fleckScale.RandomInRange; + float randomInRange3 = TrackingDef.fleckSpeed.RandomInRange; + + FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, TrackingDef.tailFleckDef, randomInRange2); + dataStatic.rotation = (currentPosition - previousPosition).AngleFlat(); + dataStatic.rotationRate = TrackingDef.fleckRotation.RandomInRange; + dataStatic.velocityAngle = velocityAngle; + dataStatic.velocitySpeed = randomInRange3; + map.flecks.CreateFleck(dataStatic); + } + } + } + lastTickPosition = ExactPosition; // 更新上一帧位置 + + // 保存移动前的精确位置 + Vector3 exactPositionBeforeMove = exactPositionInt; + + MovementTick(); // 调用追踪移动逻辑,更新 exactPositionInt (即新的 ExactPosition) + + // 检查是否超出地图边界 + if (!ExactPosition.InBounds(base.Map)) + { + // 如果超出地图,直接销毁,不触发 ImpactSomething() + Destroy(); + return; + } + + // 检查是否有东西在路径上拦截 + // ProjectileCheckForFreeInterceptBetween 会在内部处理命中,并调用 ImpactSomething() + // 所以这里不需要额外的 ImpactSomething() 调用 + object[] parameters = new object[2] { exactPositionBeforeMove, exactPositionInt }; // 传入移动前和移动后的位置 + + // 调用 ProjectileCheckForFreeInterceptBetween + // 如果它返回 true,说明有拦截,并且拦截逻辑已在内部处理。 + // 如果返回 false,说明没有拦截,子弹继续飞行。 + NonPublicFields.ProjectileCheckForFreeInterceptBetween.Invoke(this, parameters); + } + + protected override void Impact(Thing hitThing, bool blockedByShield = false) + { + // 默认Impact逻辑,可以根据需要扩展 + base.Impact(hitThing, blockedByShield); + } } } \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs index ed182f5e..9b8b3281 100644 --- a/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs +++ b/Source/WulaFallenEmpire/Projectile_WulaPenetrating.cs @@ -15,6 +15,7 @@ namespace WulaFallenEmpire // If true, this projectile will never cause friendly fire, regardless of game settings. public bool preventFriendlyFire = false; public FleckDef tailFleckDef; // 用于配置拖尾特效的 FleckDef + public int fleckDelayTicks = 10; // 拖尾特效延迟生成时间(tick) } public class Projectile_WulaLineAttack : Bullet @@ -62,26 +63,31 @@ namespace WulaFallenEmpire if (this.Destroyed) return; this.Fleck_MakeFleckTick++; - bool flag = this.Fleck_MakeFleckTick >= this.Fleck_MakeFleckTickMax; - if (flag) + // 只有当达到延迟时间后才开始生成Fleck + if (this.Fleck_MakeFleckTick >= Props.fleckDelayTicks) { - this.Fleck_MakeFleckTick = 0; + if (this.Fleck_MakeFleckTick >= (Props.fleckDelayTicks + this.Fleck_MakeFleckTickMax)) + { + this.Fleck_MakeFleckTick = Props.fleckDelayTicks; // 重置计时器,从延迟时间开始循环 + } + Map map = base.Map; int randomInRange = this.Fleck_MakeFleckNum.RandomInRange; - Vector3 vector = this.ExactPosition; // Current position of the bullet - Vector3 vector2 = this.lastTickPosition; // Previous position of the bullet + Vector3 currentPosition = this.ExactPosition; // Current position of the bullet + Vector3 previousPosition = this.lastTickPosition; // Previous position of the bullet for (int i = 0; i < randomInRange; i++) { - float num = (vector - vector2).AngleFlat(); // Angle based on movement direction - float velocityAngle = this.Fleck_Angle.RandomInRange + num; + float currentBulletAngle = ExactRotation.eulerAngles.y; // 使用子弹当前的水平旋转角度 + float fleckRotationAngle = currentBulletAngle; // Fleck 的旋转角度与子弹方向一致 + float velocityAngle = this.Fleck_Angle.RandomInRange + currentBulletAngle; // Fleck 的速度角度基于子弹方向加上随机偏移 float randomInRange2 = this.Fleck_Scale.RandomInRange; float randomInRange3 = this.Fleck_Speed.RandomInRange; if (Props?.tailFleckDef != null) { - FleckCreationData dataStatic = FleckMaker.GetDataStatic(vector, map, Props.tailFleckDef, randomInRange2); - dataStatic.rotation = (vector - vector2).AngleFlat(); + FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, Props.tailFleckDef, randomInRange2); + dataStatic.rotation = fleckRotationAngle; dataStatic.rotationRate = this.Fleck_Rotation.RandomInRange; dataStatic.velocityAngle = velocityAngle; dataStatic.velocitySpeed = randomInRange3; diff --git a/Source/WulaFallenEmpire/TrackingBulletDef.cs b/Source/WulaFallenEmpire/TrackingBulletDef.cs index 43adcf11..f94a470d 100644 --- a/Source/WulaFallenEmpire/TrackingBulletDef.cs +++ b/Source/WulaFallenEmpire/TrackingBulletDef.cs @@ -6,5 +6,15 @@ namespace WulaFallenEmpire { public float homingSpeed = 0.1f; // 追踪速度,值越大追踪越灵敏 public float initRotateAngle = 0f; // 初始旋转角度 + + public FleckDef tailFleckDef; // 拖尾特效的FleckDef + public int fleckMakeFleckTickMax = 1; // 拖尾特效的生成间隔(tick) + public int fleckDelayTicks = 10; // 拖尾特效延迟生成时间(tick) + public IntRange fleckMakeFleckNum = new IntRange(1, 1); // 每次生成拖尾特效的数量 + public FloatRange fleckAngle = new FloatRange(-180f, 180f); // 拖尾特效的初始角度范围 + public FloatRange fleckScale = new FloatRange(1f, 1f); // 拖尾特效的缩放范围 + public FloatRange fleckSpeed = new FloatRange(0f, 0f); // 拖尾特效的初始速度范围 + public FloatRange fleckRotation = new FloatRange(-180f, 180f); // 拖尾特效的旋转速度范围 + public IntRange destroyTicksAfterLosingTrack = new IntRange(60, 120); // 失去追踪后多少tick自毁 } } \ No newline at end of file diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 0fc83f50..53c40873 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -128,6 +128,8 @@ + +