整理一下
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class Thing_ExcaliburBeam : Mote
|
||||
{
|
||||
public IntVec3 targetCell;
|
||||
public Pawn caster;
|
||||
public ThingDef weaponDef;
|
||||
public float damageAmount;
|
||||
public float armorPenetration;
|
||||
public float pathWidth;
|
||||
public DamageDef damageDef;
|
||||
|
||||
// Burst shot support
|
||||
public int burstShotsTotal = 1;
|
||||
public int currentBurstShot = 0;
|
||||
|
||||
// Path cells for this burst
|
||||
private List<IntVec3> currentBurstCells;
|
||||
|
||||
private int ticksToDetonate = 0;
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref targetCell, "targetCell");
|
||||
Scribe_References.Look(ref caster, "caster");
|
||||
Scribe_Defs.Look(ref weaponDef, "weaponDef");
|
||||
Scribe_Values.Look(ref damageAmount, "damageAmount");
|
||||
Scribe_Values.Look(ref armorPenetration, "armorPenetration");
|
||||
Scribe_Values.Look(ref pathWidth, "pathWidth");
|
||||
Scribe_Defs.Look(ref damageDef, "damageDef");
|
||||
Scribe_Values.Look(ref burstShotsTotal, "burstShotsTotal", 1);
|
||||
Scribe_Values.Look(ref currentBurstShot, "currentBurstShot", 0);
|
||||
}
|
||||
|
||||
public void StartStrike(List<IntVec3> allCells, int burstIndex, int totalBursts)
|
||||
{
|
||||
if (allCells == null || !allCells.Any())
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
currentBurstCells = new List<IntVec3>(allCells);
|
||||
currentBurstShot = burstIndex;
|
||||
burstShotsTotal = totalBursts;
|
||||
|
||||
// Add a small delay before detonation for visual effect
|
||||
ticksToDetonate = 10; // 10 ticks delay before detonation
|
||||
}
|
||||
|
||||
protected override void TimeInterval(float deltaTime)
|
||||
{
|
||||
base.TimeInterval(deltaTime);
|
||||
if (ticksToDetonate > 0)
|
||||
{
|
||||
ticksToDetonate--;
|
||||
if (ticksToDetonate == 0)
|
||||
{
|
||||
Detonate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Detonate()
|
||||
{
|
||||
if (currentBurstCells == null || !currentBurstCells.Any() || Map == null)
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a copy of the list to avoid modification during iteration
|
||||
List<IntVec3> cellsToDetonate = new List<IntVec3>(currentBurstCells);
|
||||
|
||||
// Clear the current burst cells to prevent reuse
|
||||
currentBurstCells.Clear();
|
||||
|
||||
foreach (IntVec3 cell in cellsToDetonate)
|
||||
{
|
||||
if (cell.InBounds(Map))
|
||||
{
|
||||
// Apply explosion effect, but ignore the caster
|
||||
List<Thing> ignoredThings = new List<Thing>();
|
||||
if (caster != null)
|
||||
{
|
||||
ignoredThings.Add(caster);
|
||||
}
|
||||
|
||||
DamageDef explosionDamageType = damageDef ?? DamageDefOf.Bomb;
|
||||
|
||||
// Create explosion parameters with more precise settings
|
||||
GenExplosion.DoExplosion(
|
||||
center: cell,
|
||||
map: Map,
|
||||
radius: 1.2f, // Slightly larger radius for better visual effect
|
||||
damType: explosionDamageType,
|
||||
instigator: caster,
|
||||
damAmount: (int)damageAmount,
|
||||
armorPenetration: armorPenetration,
|
||||
explosionSound: null,
|
||||
weapon: weaponDef,
|
||||
projectile: null,
|
||||
intendedTarget: null,
|
||||
postExplosionSpawnThingDef: null,
|
||||
postExplosionSpawnChance: 0f,
|
||||
postExplosionSpawnThingCount: 1,
|
||||
postExplosionGasType: null,
|
||||
applyDamageToExplosionCellsNeighbors: true, // Apply damage to neighbor cells
|
||||
preExplosionSpawnThingDef: null,
|
||||
preExplosionSpawnChance: 0f,
|
||||
preExplosionSpawnThingCount: 1,
|
||||
chanceToStartFire: 0.1f, // Small chance to start fire
|
||||
damageFalloff: true, // Add damage falloff
|
||||
direction: null,
|
||||
ignoredThings: ignoredThings,
|
||||
affectedAngle: null,
|
||||
doVisualEffects: true,
|
||||
propagationSpeed: 0.5f, // Add some propagation speed for visual effect
|
||||
screenShakeFactor: 0.3f, // Add screen shake
|
||||
doSoundEffects: true,
|
||||
postExplosionSpawnThingDefWater: null,
|
||||
flammabilityChanceCurve: null,
|
||||
overrideCells: null,
|
||||
postExplosionSpawnSingleThingDef: null,
|
||||
preExplosionSpawnSingleThingDef: null);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are more bursts to come
|
||||
if (currentBurstShot < burstShotsTotal - 1)
|
||||
{
|
||||
// Prepare for next burst
|
||||
ticksToDetonate = 15; // Wait 15 ticks before next burst
|
||||
currentBurstShot++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All bursts completed, destroy the mote
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Verse;
|
||||
using RimWorld;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class VerbProperties_Excalibur : VerbProperties
|
||||
{
|
||||
public float pathWidth = 1f; // Default path width
|
||||
public DamageDef damageDef; // Custom damage type
|
||||
public float damageAmount = -1f; // Custom damage amount
|
||||
public float armorPenetration = -1f; // Custom armor penetration
|
||||
public float maxRange = 1000f; // Default max range for beams
|
||||
public string beamDefName = "ExcaliburBeam"; // Default beam def name
|
||||
}
|
||||
}
|
||||
178
Source/WulaFallenEmpire/Verb/Verb_Excalibur/Verb_Excalibur.cs
Normal file
178
Source/WulaFallenEmpire/Verb/Verb_Excalibur/Verb_Excalibur.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class Verb_Excalibur : Verb
|
||||
{
|
||||
private new Pawn CasterPawn
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.CasterPawn;
|
||||
}
|
||||
}
|
||||
|
||||
private ThingWithComps weapon
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.CasterPawn.equipment.Primary;
|
||||
}
|
||||
}
|
||||
|
||||
private QualityCategory quality
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.weapon.TryGetComp<CompQuality>().Quality;
|
||||
}
|
||||
}
|
||||
|
||||
private float damageAmountBase
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.weapon.def.tools.First<Tool>().power;
|
||||
}
|
||||
}
|
||||
|
||||
private float armorPenetrationBase
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.weapon.def.tools.First<Tool>().armorPenetration;
|
||||
}
|
||||
}
|
||||
|
||||
private float damageAmount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ExcaliburProps.damageAmount > 0)
|
||||
{
|
||||
return this.ExcaliburProps.damageAmount;
|
||||
}
|
||||
return 1.0f * this.damageAmountBase;
|
||||
}
|
||||
}
|
||||
|
||||
private float armorPenetration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ExcaliburProps.armorPenetration >= 0)
|
||||
{
|
||||
return this.ExcaliburProps.armorPenetration;
|
||||
}
|
||||
return 1.0f * this.armorPenetrationBase;
|
||||
}
|
||||
}
|
||||
|
||||
private VerbProperties_Excalibur ExcaliburProps
|
||||
{
|
||||
get
|
||||
{
|
||||
return (VerbProperties_Excalibur)this.verbProps;
|
||||
}
|
||||
}
|
||||
|
||||
protected override int ShotsPerBurst
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.verbProps.burstShotCount;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool TryCastShot()
|
||||
{
|
||||
// Calculate all affected cells once
|
||||
List<IntVec3> allAffectedCells = this.AffectedCells(this.currentTarget);
|
||||
|
||||
// Create a beam for this specific burst
|
||||
Thing_ExcaliburBeam beam = (Thing_ExcaliburBeam)GenSpawn.Spawn(DefDatabase<ThingDef>.GetNamed(this.ExcaliburProps.beamDefName, true), this.CasterPawn.Position, this.CasterPawn.Map);
|
||||
beam.caster = this.CasterPawn;
|
||||
beam.targetCell = this.currentTarget.Cell;
|
||||
beam.damageAmount = this.damageAmount;
|
||||
beam.armorPenetration = this.armorPenetration;
|
||||
beam.pathWidth = this.ExcaliburProps.pathWidth;
|
||||
beam.weaponDef = this.CasterPawn.equipment.Primary.def;
|
||||
beam.damageDef = this.ExcaliburProps.damageDef;
|
||||
beam.StartStrike(allAffectedCells, this.ShotsPerBurst, this.ShotsPerBurst);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void DrawHighlight(LocalTargetInfo target)
|
||||
{
|
||||
GenDraw.DrawFieldEdges(this.AffectedCells(target));
|
||||
}
|
||||
|
||||
private List<IntVec3> AffectedCells(LocalTargetInfo target)
|
||||
{
|
||||
this.tmpCells.Clear();
|
||||
Vector3 vector = this.CasterPawn.Position.ToVector3Shifted().Yto0();
|
||||
IntVec3 endCell = this.TargetPosition(this.CasterPawn, target);
|
||||
this.tmpCells.Clear();
|
||||
foreach (IntVec3 cell in GenSight.BresenhamCellsBetween(this.CasterPawn.Position, endCell))
|
||||
{
|
||||
if (!cell.InBounds(this.CasterPawn.Map))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (cell.GetEdifice(this.CasterPawn.Map) != null && cell.GetEdifice(this.CasterPawn.Map).def.passability == Traversability.Impassable)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Add cells around the current cell based on pathWidth
|
||||
// Convert pathWidth to proper radius for GenRadial
|
||||
float radius = Math.Max(0.5f, this.ExcaliburProps.pathWidth - 0.5f);
|
||||
foreach (IntVec3 radialCell in GenRadial.RadialCellsAround(cell, radius, true))
|
||||
{
|
||||
if (radialCell.InBounds(this.CasterPawn.Map) && !this.tmpCells.Contains(radialCell))
|
||||
{
|
||||
this.tmpCells.Add(radialCell);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.tmpCells;
|
||||
}
|
||||
|
||||
public IntVec3 TargetPosition(Pawn pawn, LocalTargetInfo currentTarget)
|
||||
{
|
||||
IntVec3 position = pawn.Position;
|
||||
IntVec3 cell = currentTarget.Cell;
|
||||
Vector3 direction = (cell - position).ToVector3().normalized;
|
||||
|
||||
// Define a maximum range to prevent infinite loops or excessively long beams
|
||||
float maxRange = this.ExcaliburProps.maxRange; // Use configurable max range
|
||||
|
||||
for (float i = 0; i < maxRange; i += 1f)
|
||||
{
|
||||
IntVec3 currentCell = (position.ToVector3() + direction * i).ToIntVec3();
|
||||
if (!currentCell.InBounds(pawn.Map))
|
||||
{
|
||||
return currentCell; // Reached map boundary
|
||||
}
|
||||
// Check for walls or other impassable terrain
|
||||
if (currentCell.GetEdifice(pawn.Map) != null && currentCell.GetEdifice(pawn.Map).def.passability == Traversability.Impassable)
|
||||
{
|
||||
return currentCell; // Hit an impassable wall
|
||||
}
|
||||
}
|
||||
return (position.ToVector3() + direction * maxRange).ToIntVec3(); // Reached max range
|
||||
}
|
||||
|
||||
private bool CanUseCell(IntVec3 c)
|
||||
{
|
||||
return c.InBounds(this.CasterPawn.Map) && c != this.CasterPawn.Position;
|
||||
}
|
||||
|
||||
private List<IntVec3> tmpCells = new List<IntVec3>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user