暂存
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../../../Data"
|
||||
},
|
||||
{
|
||||
"path": "../../../../../../../../Users/Kalo/Downloads/DrakkenLaserDrill-main/Source/MYDE_DrakkenLaserDrill"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
|
||||
17
Source/WulaFallenEmpire/VerbProperties_Wula_IonicBeam.cs
Normal file
17
Source/WulaFallenEmpire/VerbProperties_Wula_IonicBeam.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using RimWorld;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class VerbProperties_Wula_IonicBeam : VerbProperties
|
||||
{
|
||||
// --- Mode 1: Breaching Beam Properties ---
|
||||
public float breachingDamage = 200f;
|
||||
public float armorPenetration = 0.8f;
|
||||
public int breachingBeamDuration = 30; // Brief duration after hit calculation
|
||||
|
||||
// --- Mode 2: Sustained Beam Properties ---
|
||||
public float sustainedDamagePerTick = 15f;
|
||||
public int tickInterval = 10;
|
||||
public int duration = 120;
|
||||
}
|
||||
}
|
||||
148
Source/WulaFallenEmpire/Verb_Wula_BreachingBeam.cs
Normal file
148
Source/WulaFallenEmpire/Verb_Wula_BreachingBeam.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class Verb_Wula_BreachingBeam : Verb
|
||||
{
|
||||
// --- Copied from Verb_ShootBeam for visual effects ---
|
||||
private MoteDualAttached mote;
|
||||
private Effecter endEffecter;
|
||||
private Sustainer sustainer;
|
||||
|
||||
// --- Our custom state ---
|
||||
private Vector3 beamEndPoint;
|
||||
private int ticksLeft;
|
||||
private bool beamHitMapEdge; // NEW: Flag to check if the beam reached the map edge
|
||||
|
||||
private VerbProperties_Wula_IonicBeam BeamProps => (VerbProperties_Wula_IonicBeam)verbProps;
|
||||
|
||||
public override float? AimAngleOverride => (state == VerbState.Bursting) ? (beamEndPoint - caster.DrawPos).AngleFlat() : (float?)null;
|
||||
|
||||
public override void WarmupComplete()
|
||||
{
|
||||
base.WarmupComplete();
|
||||
|
||||
// --- Custom Damage Logic ---
|
||||
beamHitMapEdge = true; // Assume it will hit the edge unless stopped
|
||||
float shotAngle = (currentTarget.Cell - caster.Position).AngleFlat;
|
||||
beamEndPoint = GetMapEdgePoint(caster.Position, shotAngle);
|
||||
var cellsOnPath = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEndPoint.ToIntVec3(), verbProps.beamWidth);
|
||||
var beamEnergy = BeamProps.breachingDamage; // Local variable for calculation
|
||||
|
||||
// This loop calculates the final beam end point based on energy depletion
|
||||
foreach (var cell in cellsOnPath)
|
||||
{
|
||||
if (!cell.InBounds(caster.Map)) continue;
|
||||
var thingsToHit = cell.GetThingList(caster.Map).Where(t => CanHit(t)).ToList();
|
||||
|
||||
foreach (var thing in thingsToHit)
|
||||
{
|
||||
if (beamEnergy <= 0) break;
|
||||
|
||||
float damageToDeal = Mathf.Min(beamEnergy, thing.HitPoints);
|
||||
var dinfo = new DamageInfo(verbProps.beamDamageDef ?? DamageDefOf.Burn, damageToDeal, BeamProps.armorPenetration, shotAngle, caster, EquipmentSource);
|
||||
|
||||
thing.TakeDamage(dinfo);
|
||||
beamEnergy -= thing.HitPoints;
|
||||
}
|
||||
|
||||
if (beamEnergy <= 0)
|
||||
{
|
||||
beamEndPoint = cell.ToVector3Shifted(); // The beam stops here
|
||||
beamHitMapEdge = false; // It was stopped, so it didn't hit the edge
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Copied Effect Logic ---
|
||||
if (verbProps.beamMoteDef != null)
|
||||
{
|
||||
mote = MoteMaker.MakeInteractionOverlay(verbProps.beamMoteDef, caster, new TargetInfo(beamEndPoint.ToIntVec3(), caster.Map));
|
||||
}
|
||||
if (verbProps.soundCastBeam != null)
|
||||
{
|
||||
sustainer = verbProps.soundCastBeam.TrySpawnSustainer(SoundInfo.InMap(caster, MaintenanceType.PerTick));
|
||||
}
|
||||
}
|
||||
|
||||
public override void BurstingTick()
|
||||
{
|
||||
if (ticksLeft > 0)
|
||||
{
|
||||
// --- Copied Effect Logic ---
|
||||
if (mote != null)
|
||||
{
|
||||
mote.UpdateTargets(new TargetInfo(caster.Position, caster.Map), new TargetInfo(beamEndPoint.ToIntVec3(), caster.Map), Vector3.zero, Vector3.zero);
|
||||
mote.Maintain();
|
||||
}
|
||||
if (endEffecter == null && verbProps.beamEndEffecterDef != null)
|
||||
{
|
||||
endEffecter = verbProps.beamEndEffecterDef.Spawn(beamEndPoint.ToIntVec3(), caster.Map, Vector3.zero);
|
||||
}
|
||||
if (endEffecter != null)
|
||||
{
|
||||
endEffecter.EffectTick(new TargetInfo(beamEndPoint.ToIntVec3(), caster.Map), TargetInfo.Invalid);
|
||||
}
|
||||
sustainer?.Maintain();
|
||||
|
||||
ticksLeft--;
|
||||
if (ticksLeft <= 0)
|
||||
{
|
||||
StopBeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool TryCastShot()
|
||||
{
|
||||
// The actual "shot" is just starting the effects, damage is pre-calculated in WarmupComplete
|
||||
this.state = VerbState.Bursting;
|
||||
|
||||
// NEW: Set duration based on whether it hit the map edge
|
||||
if (beamHitMapEdge)
|
||||
{
|
||||
this.ticksLeft = BeamProps.breachingBeamDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ticksLeft = 1; // Disappears almost instantly if blocked
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void StopBeam()
|
||||
{
|
||||
this.state = VerbState.Idle;
|
||||
mote?.Destroy();
|
||||
endEffecter?.Cleanup();
|
||||
sustainer?.End();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref beamEndPoint, "beamEndPoint");
|
||||
Scribe_Values.Look(ref ticksLeft, "ticksLeft");
|
||||
Scribe_Values.Look(ref beamHitMapEdge, "beamHitMapEdge");
|
||||
}
|
||||
|
||||
private bool CanHit(Thing t)
|
||||
{
|
||||
return t != null && t.Spawned && t != caster && !t.def.IsFilth;
|
||||
}
|
||||
|
||||
private Vector3 GetMapEdgePoint(IntVec3 start, float angle)
|
||||
{
|
||||
float mapSize = Mathf.Max(caster.Map.Size.x, caster.Map.Size.z) * 1.5f;
|
||||
Vector3 direction = Quaternion.AngleAxis(angle, Vector3.up) * Vector3.forward;
|
||||
return start.ToVector3() + direction * mapSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Source/WulaFallenEmpire/Verb_Wula_SustainedBeam.cs
Normal file
137
Source/WulaFallenEmpire/Verb_Wula_SustainedBeam.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class Verb_Wula_SustainedBeam : Verb
|
||||
{
|
||||
// --- Copied from Verb_ShootBeam for visual effects ---
|
||||
private MoteDualAttached mote;
|
||||
private Effecter endEffecter;
|
||||
private Sustainer sustainer;
|
||||
|
||||
// --- Our custom state ---
|
||||
private int ticksLeft;
|
||||
private int ticksToNextDamage;
|
||||
private Vector3 beamEnd;
|
||||
|
||||
private VerbProperties_Wula_IonicBeam BeamProps => (VerbProperties_Wula_IonicBeam)verbProps;
|
||||
|
||||
public override float? AimAngleOverride => (state == VerbState.Bursting) ? (beamEnd - caster.DrawPos).AngleFlat() : (float?)null;
|
||||
|
||||
public override void WarmupComplete()
|
||||
{
|
||||
base.WarmupComplete();
|
||||
|
||||
// For sustained beam, it always reaches its max range
|
||||
var shotAngle = (currentTarget.Cell - caster.Position).AngleFlat;
|
||||
beamEnd = GetMapEdgePoint(caster.Position, shotAngle);
|
||||
|
||||
// --- Copied Effect Logic ---
|
||||
if (verbProps.beamMoteDef != null)
|
||||
{
|
||||
mote = MoteMaker.MakeInteractionOverlay(verbProps.beamMoteDef, caster, new TargetInfo(beamEnd.ToIntVec3(), caster.Map));
|
||||
}
|
||||
if (verbProps.soundCastBeam != null)
|
||||
{
|
||||
sustainer = verbProps.soundCastBeam.TrySpawnSustainer(SoundInfo.InMap(caster, MaintenanceType.PerTick));
|
||||
}
|
||||
}
|
||||
|
||||
public override void BurstingTick()
|
||||
{
|
||||
// This verb is not a standard "burst", but we use the state to manage the effect
|
||||
if (ticksLeft > 0)
|
||||
{
|
||||
// --- Copied Effect Logic ---
|
||||
if (mote != null)
|
||||
{
|
||||
mote.UpdateTargets(new TargetInfo(caster.Position, caster.Map), new TargetInfo(beamEnd.ToIntVec3(), caster.Map), Vector3.zero, Vector3.zero);
|
||||
mote.Maintain();
|
||||
}
|
||||
if (endEffecter == null && verbProps.beamEndEffecterDef != null)
|
||||
{
|
||||
endEffecter = verbProps.beamEndEffecterDef.Spawn(beamEnd.ToIntVec3(), caster.Map, Vector3.zero);
|
||||
}
|
||||
if (endEffecter != null)
|
||||
{
|
||||
endEffecter.EffectTick(new TargetInfo(beamEnd.ToIntVec3(), caster.Map), TargetInfo.Invalid);
|
||||
}
|
||||
sustainer?.Maintain();
|
||||
|
||||
// --- Custom Damage Logic ---
|
||||
ticksLeft--;
|
||||
ticksToNextDamage--;
|
||||
if (ticksToNextDamage <= 0)
|
||||
{
|
||||
ApplyDamage();
|
||||
ticksToNextDamage = BeamProps.tickInterval;
|
||||
}
|
||||
|
||||
if (ticksLeft <= 0)
|
||||
{
|
||||
StopBeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool TryCastShot()
|
||||
{
|
||||
this.state = VerbState.Bursting;
|
||||
this.ticksLeft = BeamProps.duration;
|
||||
this.ticksToNextDamage = 0; // First damage tick happens immediately
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ApplyDamage()
|
||||
{
|
||||
var shotAngle = (beamEnd - caster.DrawPos).AngleFlat();
|
||||
var dinfo = new DamageInfo(verbProps.beamDamageDef ?? DamageDefOf.Burn, BeamProps.sustainedDamagePerTick, BeamProps.armorPenetration, shotAngle, caster, EquipmentSource);
|
||||
var cellsInBeam = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEnd.ToIntVec3(), verbProps.beamWidth);
|
||||
|
||||
foreach (var cell in cellsInBeam)
|
||||
{
|
||||
if (!cell.InBounds(caster.Map)) continue;
|
||||
|
||||
var thingsToHit = cell.GetThingList(caster.Map).Where(t => CanHit(t)).ToList();
|
||||
foreach (var thing in thingsToHit)
|
||||
{
|
||||
thing.TakeDamage(dinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StopBeam()
|
||||
{
|
||||
this.state = VerbState.Idle;
|
||||
mote?.Destroy();
|
||||
endEffecter?.Cleanup();
|
||||
sustainer?.End();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref ticksLeft, "ticksLeft", 0);
|
||||
Scribe_Values.Look(ref ticksToNextDamage, "ticksToNextDamage", 0);
|
||||
Scribe_Values.Look(ref beamEnd, "beamEnd");
|
||||
}
|
||||
|
||||
private bool CanHit(Thing t)
|
||||
{
|
||||
return t != null && t.Spawned && t != caster && !t.def.IsFilth;
|
||||
}
|
||||
|
||||
private Vector3 GetMapEdgePoint(IntVec3 start, float angle)
|
||||
{
|
||||
float mapSize = Mathf.Max(caster.Map.Size.x, caster.Map.Size.z) * 1.5f;
|
||||
Vector3 direction = Quaternion.AngleAxis(angle, Vector3.up) * Vector3.forward;
|
||||
return start.toVector3() + direction * mapSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Source/WulaFallenEmpire/WulaBeamUtility.cs
Normal file
64
Source/WulaFallenEmpire/WulaBeamUtility.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public static class WulaBeamUtility
|
||||
{
|
||||
private static readonly Material BeamMaterial = MaterialPool.MatFrom(GenDraw.LineTexPath, ShaderDatabase.Transparent, Color.white);
|
||||
|
||||
// A more advanced method to get all cells in a rectangular area
|
||||
public static IEnumerable<IntVec3> GetCellsInBeamArea(IntVec3 start, IntVec3 end, int width)
|
||||
{
|
||||
if (width <= 1)
|
||||
{
|
||||
return GenGrid.PointsOnLine(start, end).Distinct();
|
||||
}
|
||||
|
||||
var beamLine = GenGrid.PointsOnLine(start, end).ToList();
|
||||
var allCells = new HashSet<IntVec3>(beamLine);
|
||||
var halfWidth = (width - 1) / 2;
|
||||
|
||||
if (halfWidth == 0) return allCells;
|
||||
|
||||
var angle = (end - start).AngleFlat;
|
||||
var perpendicularAngle = angle - 90f;
|
||||
|
||||
foreach (var cell in beamLine)
|
||||
{
|
||||
for (int i = 1; i <= halfWidth; i++)
|
||||
{
|
||||
var offset = Vector3.forward.RotatedBy(perpendicularAngle) * i;
|
||||
allCells.Add((cell.ToVector3() + offset).ToIntVec3());
|
||||
allCells.Add((cell.ToVector3() - offset).ToIntVec3());
|
||||
}
|
||||
}
|
||||
return allCells;
|
||||
}
|
||||
|
||||
// A shared drawing method
|
||||
public static void DrawBeam(Vector3 start, Vector3 end, Color color, float width)
|
||||
{
|
||||
var material = BeamMaterial;
|
||||
if (material.color != color)
|
||||
{
|
||||
material = MaterialPool.MatFrom(GenDraw.LineTexPath, ShaderDatabase.Transparent, color);
|
||||
}
|
||||
|
||||
var matrix = default(Matrix4x4);
|
||||
var distance = Vector3.Distance(start, end);
|
||||
var angle = (end - start).AngleFlat();
|
||||
|
||||
matrix.SetTRS(
|
||||
pos: start + (end - start) / 2f,
|
||||
q: Quaternion.AngleAxis(angle, Vector3.up),
|
||||
s: new Vector3(width, 1f, distance)
|
||||
);
|
||||
|
||||
Graphics.DrawMesh(MeshPool.plane10, matrix, material, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user