暂存
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
<ThingDef ParentName="MoteBase">
|
||||||
|
<defName>ExcaliburBeam</defName>
|
||||||
|
<thingClass>WulaFallenEmpire.Thing_ExcaliburBeam</thingClass>
|
||||||
|
<label>Excalibur Beam</label>
|
||||||
|
<altitudeLayer>MoteOverhead</altitudeLayer>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Mote/PowerBeam</texPath>
|
||||||
|
<shaderType>MoteGlow</shaderType>
|
||||||
|
</graphicData>
|
||||||
|
<drawOffscreen>true</drawOffscreen>
|
||||||
|
<mote>
|
||||||
|
<fadeInTime>0.5</fadeInTime>
|
||||||
|
<solidTime>9.3</solidTime>
|
||||||
|
<fadeOutTime>1.0</fadeOutTime>
|
||||||
|
</mote>
|
||||||
|
</ThingDef>
|
||||||
|
</Defs>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
离子武器最终正确架构配置示例 (V17.0)
|
离子武器最终正确架构配置示例 (V17.0)
|
||||||
=====================================================================
|
=====================================================================
|
||||||
说明:
|
说明:
|
||||||
- 核心架构: 自定义 VerbProperties (VerbProperties_Wula_IonicBeam)
|
- 核心架构: 自定义 VerbProperties (VerbProperties_Excalibur)
|
||||||
- 伤害逻辑: 完全在C#中自定义,包括路径伤害和能量消耗。
|
- 伤害逻辑: 完全在C#中自定义,包括路径伤害和能量消耗。
|
||||||
- 特效逻辑: 主要由我们自己在VerbProperties中定义的参数手动控制。
|
- 特效逻辑: 主要由我们自己在VerbProperties中定义的参数手动控制。
|
||||||
-->
|
-->
|
||||||
@@ -28,90 +28,56 @@
|
|||||||
<AccuracyLong>1</AccuracyLong>
|
<AccuracyLong>1</AccuracyLong>
|
||||||
<RangedWeapon_Cooldown>1.5</RangedWeapon_Cooldown>
|
<RangedWeapon_Cooldown>1.5</RangedWeapon_Cooldown>
|
||||||
</statBases>
|
</statBases>
|
||||||
|
<weaponTags>
|
||||||
|
<li>WulaExcalibur</li>
|
||||||
|
</weaponTags>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
<!-- ==================== 模式一: 离子突破光束枪 (爆发贯穿 + 路径爆炸) ==================== -->
|
|
||||||
|
|
||||||
<ThingDef ParentName="Wula_BaseIonicGun">
|
<ThingDef ParentName="Wula_BaseIonicGun">
|
||||||
<defName>WULA_Weapon_BreachingBeamGun</defName>
|
<defName>WULA_Weapon_Excalibur</defName>
|
||||||
<label>离子突破光束枪</label>
|
<label>王者之剑</label>
|
||||||
<description>发射一道高能离子束,能够烧穿路径上的多个目标,直到能量耗尽。光束路径上会周期性地引发小规模湮灭反应。</description>
|
<description>一把传奇的剑,能够释放出沿路径爆炸的能量。</description>
|
||||||
<verbs>
|
<graphicData>
|
||||||
<li Class="WulaFallenEmpire.VerbProperties_Wula_IonicBeam">
|
<texPath>Wula/Weapon/WULA_RW_DM_AR</texPath>
|
||||||
<verbClass>WulaFallenEmpire.Verb_Wula_BreachingBeam</verbClass>
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
</graphicData>
|
||||||
<!-- 基础参数 -->
|
<uiIconScale>1.5</uiIconScale>
|
||||||
<hasStandardCommand>true</hasStandardCommand>
|
<equippedAngleOffset>45</equippedAngleOffset>
|
||||||
<warmupTime>2.5</warmupTime>
|
<tools>
|
||||||
<range>40</range>
|
<li>
|
||||||
<burstShotCount>1</burstShotCount>
|
<label>剑刃</label>
|
||||||
<soundCast>BeamGraser_Shooting</soundCast>
|
<capacities>
|
||||||
|
<li>Cut</li>
|
||||||
<!-- 我们自定义的伤害参数 -->
|
</capacities>
|
||||||
<breachingDamage>300</breachingDamage>
|
<power>15</power>
|
||||||
<armorPenetration>0.95</armorPenetration>
|
<cooldownTime>2</cooldownTime>
|
||||||
<breachingBeamDuration>45</breachingBeamDuration>
|
|
||||||
|
|
||||||
<!-- 路径爆炸参数 -->
|
|
||||||
<explosionEnabled>true</explosionEnabled>
|
|
||||||
<explosionTickInterval>10</explosionTickInterval>
|
|
||||||
<explosionDamageDef>Wula_Dark_Matter</explosionDamageDef>
|
|
||||||
<explosionEnergyCostRatio>0.1</explosionEnergyCostRatio>
|
|
||||||
|
|
||||||
<!-- 手动特效参数 -->
|
|
||||||
<explosionHeatEnergyPerCell>10</explosionHeatEnergyPerCell>
|
|
||||||
<explosionCellFleck>BlastFlame</explosionCellFleck>
|
|
||||||
<soundExplosion>Explosion_Flame</soundExplosion>
|
|
||||||
|
|
||||||
<!-- 光束视觉特效参数 -->
|
|
||||||
<soundCastBeam>BeamGraser_Shooting</soundCastBeam>
|
|
||||||
<muzzleFlashScale>12</muzzleFlashScale>
|
|
||||||
<beamWidth>3</beamWidth>
|
|
||||||
<beamMoteDef>Mote_GraserBeamBase</beamMoteDef>
|
|
||||||
<beamEndEffecterDef>GraserBeam_End</beamEndEffecterDef>
|
|
||||||
</li>
|
</li>
|
||||||
</verbs>
|
</tools>
|
||||||
</ThingDef>
|
|
||||||
|
|
||||||
<!-- ==================== 模式二: 离子灼烧光束枪 (持续伤害 + 路径爆炸) ==================== -->
|
|
||||||
|
|
||||||
<ThingDef ParentName="Wula_BaseIonicGun">
|
|
||||||
<defName>WULA_Weapon_SustainedBeamGun</defName>
|
|
||||||
<label>离子灼烧光束枪</label>
|
|
||||||
<description>投射一道持续存在的离子场,对作用范围内的所有敌人进行周期性灼烧,并引发连续的能量爆炸。</description>
|
|
||||||
<verbs>
|
<verbs>
|
||||||
<li Class="WulaFallenEmpire.VerbProperties_Wula_IonicBeam">
|
<li Class="WulaFallenEmpire.VerbProperties_Excalibur">
|
||||||
<verbClass>WulaFallenEmpire.Verb_Wula_SustainedBeam</verbClass>
|
<verbClass>WulaFallenEmpire.Verb_Excalibur</verbClass>
|
||||||
|
|
||||||
<!-- 基础参数 -->
|
|
||||||
<hasStandardCommand>true</hasStandardCommand>
|
<hasStandardCommand>true</hasStandardCommand>
|
||||||
|
<range>25.9</range>
|
||||||
<warmupTime>1.5</warmupTime>
|
<warmupTime>1.5</warmupTime>
|
||||||
<range>30</range>
|
<burstShotCount>10</burstShotCount>
|
||||||
|
<ticksBetweenBurstShots>50</ticksBetweenBurstShots>
|
||||||
<!-- 我们自定义的伤害参数 -->
|
<soundCast>ChargeLance_Fire</soundCast>
|
||||||
<sustainedDamagePerTick>15</sustainedDamagePerTick>
|
<soundCastTail>GunTail_Heavy</soundCastTail>
|
||||||
<tickInterval>15</tickInterval>
|
<targetParams>
|
||||||
<duration>240</duration>
|
<canTargetLocations>true</canTargetLocations>
|
||||||
<armorPenetration>0.5</armorPenetration>
|
</targetParams>
|
||||||
|
<accuracyTouch>0.7</accuracyTouch>
|
||||||
<!-- 路径爆炸参数 -->
|
<accuracyShort>0.6</accuracyShort>
|
||||||
<explosionEnabled>true</explosionEnabled>
|
<accuracyMedium>0.5</accuracyMedium>
|
||||||
<explosionTickInterval>25</explosionTickInterval>
|
<accuracyLong>0.4</accuracyLong>
|
||||||
<explosionDamageDef>Wula_Dark_Matter_Flame</explosionDamageDef>
|
<minRange>3</minRange>
|
||||||
|
<requireLineOfSight>true</requireLineOfSight>
|
||||||
<!-- 手动特效参数 -->
|
<pathWidth>1</pathWidth>
|
||||||
<explosionHeatEnergyPerCell>10</explosionHeatEnergyPerCell>
|
<damageDef>Vaporize</damageDef>
|
||||||
<explosionCellFleck>BlastFlame</explosionCellFleck>
|
<damageAmount>50</damageAmount>
|
||||||
<soundExplosion>Explosion_Flame</soundExplosion>
|
<armorPenetration>0.3</armorPenetration>
|
||||||
|
|
||||||
<!-- 光束视觉特效参数 -->
|
|
||||||
<soundCastBeam>BeamGraser_Shooting</soundCastBeam>
|
|
||||||
<muzzleFlashScale>9</muzzleFlashScale>
|
|
||||||
<beamWidth>3</beamWidth>
|
|
||||||
<beamMoteDef>Mote_GraserBeamBase</beamMoteDef>
|
|
||||||
<beamEndEffecterDef>GraserBeam_End</beamEndEffecterDef>
|
|
||||||
</li>
|
</li>
|
||||||
</verbs>
|
</verbs>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
</Defs>
|
</Defs>
|
||||||
File diff suppressed because one or more lines are too long
97
Source/WulaFallenEmpire/Thing_ExcaliburBeam.cs
Normal file
97
Source/WulaFallenEmpire/Thing_ExcaliburBeam.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
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)
|
||||||
|
{
|
||||||
|
currentBurstCells = allCells;
|
||||||
|
currentBurstShot = burstIndex;
|
||||||
|
burstShotsTotal = totalBursts;
|
||||||
|
ticksToDetonate = 1; // Start detonation immediately
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For this burst, we'll detonate all cells
|
||||||
|
foreach (IntVec3 cell in currentBurstCells)
|
||||||
|
{
|
||||||
|
if (cell.InBounds(Map))
|
||||||
|
{
|
||||||
|
// Apply explosion effect, but ignore the caster
|
||||||
|
List<Thing> ignoredThings = new List<Thing> { caster };
|
||||||
|
DamageDef explosionDamageType = damageDef ?? DamageDefOf.Bomb;
|
||||||
|
GenExplosion.DoExplosion(center: cell, map: Map, radius: 0.9f, 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: false,
|
||||||
|
preExplosionSpawnThingDef: null, preExplosionSpawnChance: 0f,
|
||||||
|
preExplosionSpawnThingCount: 1, chanceToStartFire: 0f,
|
||||||
|
damageFalloff: false, direction: null, ignoredThings: ignoredThings,
|
||||||
|
affectedAngle: null, doVisualEffects: true, propagationSpeed: 0f,
|
||||||
|
screenShakeFactor: 0f, doSoundEffects: true, postExplosionSpawnThingDefWater: null,
|
||||||
|
flammabilityChanceCurve: null, overrideCells: null, postExplosionSpawnSingleThingDef: null, preExplosionSpawnSingleThingDef: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Source/WulaFallenEmpire/Verb/VerbProperties_Excalibur.cs
Normal file
13
Source/WulaFallenEmpire/Verb/VerbProperties_Excalibur.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
201
Source/WulaFallenEmpire/Verb/Verb_Excalibur.cs
Normal file
201
Source/WulaFallenEmpire/Verb/Verb_Excalibur.cs
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// Use the damageAmount from VerbProperties if set, otherwise use the base damage
|
||||||
|
if (this.ExcaliburProps.damageAmount > 0)
|
||||||
|
{
|
||||||
|
return this.ExcaliburProps.damageAmount;
|
||||||
|
}
|
||||||
|
// Removed AncotUtility.QualityFactor, using a simple multiplier for now
|
||||||
|
return 1.0f * this.damageAmountBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float armorPenetration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Use the armorPenetration from VerbProperties if set, otherwise use the base value
|
||||||
|
if (this.ExcaliburProps.armorPenetration >= 0)
|
||||||
|
{
|
||||||
|
return this.ExcaliburProps.armorPenetration;
|
||||||
|
}
|
||||||
|
// Removed AncotUtility.QualityFactor, using a simple multiplier for now
|
||||||
|
return 1.0f * this.armorPenetrationBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily commented out CompWeaponCharge related code
|
||||||
|
/*
|
||||||
|
public CompWeaponCharge compCharge
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.weapon.TryGetComp<CompWeaponCharge>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private VerbProperties_Excalibur ExcaliburProps
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (VerbProperties_Excalibur)this.verbProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryCastShot()
|
||||||
|
{
|
||||||
|
// Temporarily commented out CompWeaponCharge related code
|
||||||
|
/*
|
||||||
|
bool flag = this.compCharge != null && !this.compCharge.CanBeUsed;
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
CompWeaponCharge compCharge = this.compCharge;
|
||||||
|
if (compCharge != null)
|
||||||
|
{
|
||||||
|
compCharge.UsedOnce();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 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("ExcaliburBeam", 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.BurstShotsLeft, this.BurstShotCount);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
/*
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawHighlight(LocalTargetInfo target)
|
||||||
|
{
|
||||||
|
GenDraw.DrawFieldEdges(this.AffectedCells(target), 2900);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 1000f; // Increased range for longer beams
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using RimWorld;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// --- NEW: Explosion Path Properties (for both modes) ---
|
|
||||||
public bool explosionEnabled = false;
|
|
||||||
public int explosionTickInterval = 15;
|
|
||||||
public DamageDef explosionDamageDef;
|
|
||||||
public float explosionEnergyCostRatio = 0.5f; // Only for Breaching Beam
|
|
||||||
|
|
||||||
// Manual explosion effect properties
|
|
||||||
public float explosionHeatEnergyPerCell = 0;
|
|
||||||
public FleckDef explosionCellFleck;
|
|
||||||
public Color explosionColorCenter = Color.white;
|
|
||||||
public Color explosionColorEdge = Color.white;
|
|
||||||
public SoundDef soundExplosion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
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;
|
|
||||||
private int explosionTicks;
|
|
||||||
private float beamEnergy;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
// --- Initial Damage and Path Calculation ---
|
|
||||||
beamHitMapEdge = true;
|
|
||||||
float shotAngle = (currentTarget.Cell - caster.Position).AngleFlat;
|
|
||||||
beamEndPoint = GetMapEdgePoint(caster.Position, shotAngle);
|
|
||||||
var cellsOnPath = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEndPoint.ToIntVec3(), (int)verbProps.beamWidth);
|
|
||||||
this.beamEnergy = BeamProps.breachingDamage;
|
|
||||||
|
|
||||||
// This loop calculates the final beam end point based on the initial piercing damage
|
|
||||||
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, null, EquipmentSource?.def);
|
|
||||||
|
|
||||||
thing.TakeDamage(dinfo);
|
|
||||||
beamEnergy -= thing.HitPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beamEnergy <= 0)
|
|
||||||
{
|
|
||||||
beamEndPoint = cell.ToVector3Shifted();
|
|
||||||
beamHitMapEdge = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Start Visual Effects ---
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
// --- Maintain Visual Effects ---
|
|
||||||
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();
|
|
||||||
|
|
||||||
// --- Path Explosion Logic ---
|
|
||||||
if (BeamProps.explosionEnabled)
|
|
||||||
{
|
|
||||||
explosionTicks--;
|
|
||||||
if (explosionTicks <= 0)
|
|
||||||
{
|
|
||||||
ApplyPathExplosionDamage();
|
|
||||||
explosionTicks = BeamProps.explosionTickInterval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ticksLeft--;
|
|
||||||
if (ticksLeft <= 0)
|
|
||||||
{
|
|
||||||
StopBeam();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool TryCastShot()
|
|
||||||
{
|
|
||||||
this.state = VerbState.Bursting;
|
|
||||||
|
|
||||||
if (beamHitMapEdge)
|
|
||||||
{
|
|
||||||
this.ticksLeft = BeamProps.breachingBeamDuration;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.ticksLeft = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.explosionTicks = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopBeam()
|
|
||||||
{
|
|
||||||
this.state = VerbState.Idle;
|
|
||||||
mote?.Destroy();
|
|
||||||
endEffecter?.Cleanup();
|
|
||||||
sustainer?.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyPathExplosionDamage()
|
|
||||||
{
|
|
||||||
if (this.beamEnergy <= 0 || BeamProps.explosionDamageDef == null) return;
|
|
||||||
|
|
||||||
var pathCells = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEndPoint.ToIntVec3(), (int)verbProps.beamWidth);
|
|
||||||
var shotAngle = (beamEndPoint - caster.DrawPos).AngleFlat();
|
|
||||||
var explosionDamageDef = BeamProps.explosionDamageDef;
|
|
||||||
|
|
||||||
foreach (var cell in pathCells)
|
|
||||||
{
|
|
||||||
if (this.beamEnergy <= 0) break;
|
|
||||||
if (!cell.InBounds(caster.Map)) continue;
|
|
||||||
|
|
||||||
// Performance optimization: don't create explosions on every single cell of the path
|
|
||||||
if (cell.GetHashCode() % 2 != 0) continue;
|
|
||||||
|
|
||||||
var thingsToHit = cell.GetThingList(caster.Map).Where(t => CanHit(t)).ToList();
|
|
||||||
foreach (var thing in thingsToHit)
|
|
||||||
{
|
|
||||||
if (this.beamEnergy <= 0) break;
|
|
||||||
|
|
||||||
var dinfo = new DamageInfo(explosionDamageDef, explosionDamageDef.defaultDamage, explosionDamageDef.defaultArmorPenetration, shotAngle, caster, null, EquipmentSource?.def);
|
|
||||||
float damageDealt = Mathf.Min(thing.HitPoints, dinfo.Amount);
|
|
||||||
thing.TakeDamage(dinfo);
|
|
||||||
|
|
||||||
this.beamEnergy -= damageDealt * BeamProps.explosionEnergyCostRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(explosionDamageDef?.explosionCellMote != null)
|
|
||||||
{
|
|
||||||
FleckMaker.Static(cell, caster.Map, explosionDamageDef.explosionCellMote);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData()
|
|
||||||
{
|
|
||||||
base.ExposeData();
|
|
||||||
Scribe_Values.Look(ref beamEndPoint, "beamEndPoint");
|
|
||||||
Scribe_Values.Look(ref ticksLeft, "ticksLeft");
|
|
||||||
Scribe_Values.Look(ref beamHitMapEdge, "beamHitMapEdge");
|
|
||||||
Scribe_Values.Look(ref explosionTicks, "explosionTicks");
|
|
||||||
Scribe_Values.Look(ref beamEnergy, "beamEnergy");
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
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 int explosionTicks;
|
|
||||||
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();
|
|
||||||
|
|
||||||
var shotAngle = (currentTarget.Cell - caster.Position).AngleFlat;
|
|
||||||
beamEnd = GetMapEdgePoint(caster.Position, shotAngle);
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
if (ticksLeft > 0)
|
|
||||||
{
|
|
||||||
// --- Maintain Visual Effects ---
|
|
||||||
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();
|
|
||||||
|
|
||||||
// --- Beam Damage Logic ---
|
|
||||||
ticksToNextDamage--;
|
|
||||||
if (ticksToNextDamage <= 0)
|
|
||||||
{
|
|
||||||
ApplyBeamDamage();
|
|
||||||
ticksToNextDamage = BeamProps.tickInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Path Explosion Logic ---
|
|
||||||
if (BeamProps.explosionEnabled)
|
|
||||||
{
|
|
||||||
explosionTicks--;
|
|
||||||
if (explosionTicks <= 0)
|
|
||||||
{
|
|
||||||
ApplyPathExplosionDamage();
|
|
||||||
explosionTicks = BeamProps.explosionTickInterval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ticksLeft--;
|
|
||||||
if (ticksLeft <= 0)
|
|
||||||
{
|
|
||||||
StopBeam();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool TryCastShot()
|
|
||||||
{
|
|
||||||
this.state = VerbState.Bursting;
|
|
||||||
this.ticksLeft = BeamProps.duration;
|
|
||||||
this.ticksToNextDamage = 0;
|
|
||||||
this.explosionTicks = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopBeam()
|
|
||||||
{
|
|
||||||
this.state = VerbState.Idle;
|
|
||||||
mote?.Destroy();
|
|
||||||
endEffecter?.Cleanup();
|
|
||||||
sustainer?.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyBeamDamage()
|
|
||||||
{
|
|
||||||
var shotAngle = (beamEnd - caster.DrawPos).AngleFlat();
|
|
||||||
var dinfo = new DamageInfo(verbProps.beamDamageDef ?? DamageDefOf.Burn, BeamProps.sustainedDamagePerTick, BeamProps.armorPenetration, shotAngle, caster, null, EquipmentSource?.def);
|
|
||||||
var cellsInBeam = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEnd.ToIntVec3(), (int)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 ApplyPathExplosionDamage()
|
|
||||||
{
|
|
||||||
if (BeamProps.explosionDamageDef == null) return;
|
|
||||||
|
|
||||||
var pathCells = WulaBeamUtility.GetCellsInBeamArea(caster.Position, beamEnd.ToIntVec3(), (int)verbProps.beamWidth);
|
|
||||||
var shotAngle = (beamEnd - caster.DrawPos).AngleFlat();
|
|
||||||
var explosionDamageDef = BeamProps.explosionDamageDef;
|
|
||||||
|
|
||||||
foreach (var cell in pathCells)
|
|
||||||
{
|
|
||||||
if (!cell.InBounds(caster.Map)) continue;
|
|
||||||
|
|
||||||
if (cell.GetHashCode() % 3 != 0) continue;
|
|
||||||
|
|
||||||
var thingsToHit = cell.GetThingList(caster.Map).Where(t => CanHit(t)).ToList();
|
|
||||||
foreach (var thing in thingsToHit)
|
|
||||||
{
|
|
||||||
var dinfo = new DamageInfo(explosionDamageDef, explosionDamageDef.defaultDamage, explosionDamageDef.defaultArmorPenetration, shotAngle, caster, null, EquipmentSource?.def);
|
|
||||||
thing.TakeDamage(dinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(BeamProps.explosionCellFleck != null)
|
|
||||||
{
|
|
||||||
FleckMaker.Static(cell, caster.Map, BeamProps.explosionCellFleck);
|
|
||||||
}
|
|
||||||
if (BeamProps.soundExplosion != null)
|
|
||||||
{
|
|
||||||
BeamProps.soundExplosion.PlayOneShot(new TargetInfo(cell, caster.Map));
|
|
||||||
}
|
|
||||||
GenTemperature.PushHeat(cell, caster.Map, BeamProps.explosionHeatEnergyPerCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData()
|
|
||||||
{
|
|
||||||
base.ExposeData();
|
|
||||||
Scribe_Values.Look(ref ticksLeft, "ticksLeft", 0);
|
|
||||||
Scribe_Values.Look(ref ticksToNextDamage, "ticksToNextDamage", 0);
|
|
||||||
Scribe_Values.Look(ref explosionTicks, "explosionTicks");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
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)
|
|
||||||
{
|
|
||||||
var beamLine = GenSight.PointsOnLineOfSight(start, end);
|
|
||||||
if (width <= 1)
|
|
||||||
{
|
|
||||||
return beamLine.Distinct();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -191,12 +191,12 @@
|
|||||||
<Compile Include="CompForceTargetable.cs" />
|
<Compile Include="CompForceTargetable.cs" />
|
||||||
<Compile Include="Patch_ForceTargetable.cs" />
|
<Compile Include="Patch_ForceTargetable.cs" />
|
||||||
<Compile Include="Patch_ArmedShuttle_ForceTargetable.cs" />
|
<Compile Include="Patch_ArmedShuttle_ForceTargetable.cs" />
|
||||||
<Compile Include="VerbProperties_Wula_IonicBeam.cs" />
|
<Compile Include="Verb\VerbProperties_Excalibur.cs" />
|
||||||
<Compile Include="Verb_Wula_BreachingBeam.cs" />
|
<Compile Include="Verb\Verb_Excalibur.cs" />
|
||||||
<Compile Include="Verb_Wula_SustainedBeam.cs" />
|
</ItemGroup>
|
||||||
<Compile Include="WulaBeamUtility.cs" />
|
<ItemGroup>
|
||||||
|
<Compile Include="Thing_ExcaliburBeam.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||||
|
|||||||
Reference in New Issue
Block a user