148 lines
5.5 KiB
C#
148 lines
5.5 KiB
C#
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;
|
|
}
|
|
}
|
|
} |