174 lines
4.7 KiB
C#
174 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace RoR2;
|
|
|
|
public class BodySplitter
|
|
{
|
|
public CharacterBody body;
|
|
|
|
public float moneyMultiplier;
|
|
|
|
private int _count = 1;
|
|
|
|
public readonly MasterSummon masterSummon;
|
|
|
|
private Dictionary<CharacterBody, Vector3> spawnedBodyVelocity = new Dictionary<CharacterBody, Vector3>();
|
|
|
|
public int count
|
|
{
|
|
get
|
|
{
|
|
return _count;
|
|
}
|
|
set
|
|
{
|
|
if (value <= 0)
|
|
{
|
|
throw new ArgumentException("'value' cannot be non-positive.", "value");
|
|
}
|
|
_count = value;
|
|
}
|
|
}
|
|
|
|
public Vector3 splinterInitialVelocityLocal { get; set; } = Vector3.zero;
|
|
|
|
|
|
public float minSpawnCircleRadius { get; set; }
|
|
|
|
public BodySplitter()
|
|
{
|
|
masterSummon = new MasterSummon
|
|
{
|
|
masterPrefab = null,
|
|
ignoreTeamMemberLimit = false,
|
|
useAmbientLevel = null,
|
|
teamIndexOverride = null
|
|
};
|
|
}
|
|
|
|
public void Perform()
|
|
{
|
|
PerformInternal(masterSummon);
|
|
}
|
|
|
|
private void PerformInternal(MasterSummon masterSummon)
|
|
{
|
|
if ((object)body == null)
|
|
{
|
|
throw new InvalidOperationException("'body' is null.");
|
|
}
|
|
if (!body)
|
|
{
|
|
throw new InvalidOperationException("'body' is an invalid object.");
|
|
}
|
|
GameObject masterPrefab = masterSummon.masterPrefab;
|
|
CharacterMaster obj = masterPrefab.GetComponent<CharacterMaster>() ?? throw new InvalidOperationException("'splinterMasterPrefab' does not have a CharacterMaster component.");
|
|
if (!obj.masterIndex.isValid)
|
|
{
|
|
throw new InvalidOperationException("'splinterMasterPrefab' is not registered with MasterCatalog.");
|
|
}
|
|
if ((object)MasterCatalog.GetMasterPrefab(obj.masterIndex) != masterPrefab)
|
|
{
|
|
throw new InvalidOperationException("'splinterMasterPrefab' is not a prefab.");
|
|
}
|
|
Vector3 position = body.transform.position;
|
|
float y = Quaternion.LookRotation(body.inputBank.aimDirection).eulerAngles.y;
|
|
GameObject bodyPrefab = obj.bodyPrefab;
|
|
bodyPrefab.GetComponent<CharacterBody>();
|
|
float num = CalcBodyXZRadius(bodyPrefab);
|
|
float a = 0f;
|
|
if (count > 1)
|
|
{
|
|
a = num / Mathf.Sin(MathF.PI / (float)count);
|
|
}
|
|
a = Mathf.Max(a, minSpawnCircleRadius);
|
|
masterSummon.summonerBodyObject = body.gameObject;
|
|
masterSummon.inventoryToCopy = body.inventory;
|
|
masterSummon.loadout = (body.master ? body.master.loadout : null);
|
|
masterSummon.inventoryItemCopyFilter = CopyItemFilter;
|
|
foreach (float item in new DegreeSlices(count, 0.5f))
|
|
{
|
|
Quaternion quaternion = Quaternion.Euler(0f, y + item + 180f, 0f);
|
|
Vector3 vector = quaternion * Vector3.forward;
|
|
float num2 = a;
|
|
if (Physics.Raycast(new Ray(position, vector), out var hitInfo, a + num, LayerIndex.world.intVal, QueryTriggerInteraction.Ignore))
|
|
{
|
|
num2 = hitInfo.distance - num;
|
|
}
|
|
Vector3 position2 = position + vector * num2;
|
|
masterSummon.position = position2;
|
|
masterSummon.rotation = quaternion;
|
|
try
|
|
{
|
|
CharacterMaster characterMaster = masterSummon.Perform();
|
|
if ((bool)characterMaster)
|
|
{
|
|
CharacterBody characterBody = characterMaster.GetBody();
|
|
if ((bool)characterBody)
|
|
{
|
|
spawnedBodyVelocity.Add(characterBody, quaternion * splinterInitialVelocityLocal);
|
|
characterMaster.money = (uint)Mathf.FloorToInt((float)body.master.money * moneyMultiplier);
|
|
characterBody.characterMotor.onMotorStart += OnCharacterMotorStart;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception message)
|
|
{
|
|
Debug.LogError(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnCharacterMotorStart(CharacterBody characterBody)
|
|
{
|
|
if (spawnedBodyVelocity.TryGetValue(characterBody, out var value))
|
|
{
|
|
AddBodyVelocity(characterBody, value);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Split characterBody has not stored split velocity");
|
|
}
|
|
}
|
|
|
|
private static float CalcBodyXZRadius(GameObject bodyPrefab)
|
|
{
|
|
Collider component = bodyPrefab.GetComponent<Collider>();
|
|
if (!component)
|
|
{
|
|
return 0f;
|
|
}
|
|
Vector3 position = bodyPrefab.transform.position;
|
|
Bounds bounds = component.bounds;
|
|
Vector3 min = bounds.min;
|
|
Vector3 max = bounds.max;
|
|
return Mathf.Max(Mathf.Max(Mathf.Max(Mathf.Max(0f, position.x - min.x), position.z - min.z), max.x - position.x), max.z - position.z);
|
|
}
|
|
|
|
private static void AddBodyVelocity(CharacterBody body, Vector3 additionalVelocity)
|
|
{
|
|
IPhysMotor component = body.GetComponent<IPhysMotor>();
|
|
if (component != null)
|
|
{
|
|
PhysForceInfo physForceInfo = PhysForceInfo.Create();
|
|
physForceInfo.force = additionalVelocity;
|
|
physForceInfo.massIsOne = true;
|
|
physForceInfo.ignoreGroundStick = true;
|
|
physForceInfo.disableAirControlUntilCollision = false;
|
|
component.ApplyForceImpulse(in physForceInfo);
|
|
}
|
|
}
|
|
|
|
private static bool CopyItemFilter(ItemIndex itemIndex)
|
|
{
|
|
ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
|
|
if ((bool)itemDef)
|
|
{
|
|
return itemDef.tier == ItemTier.NoTier;
|
|
}
|
|
return false;
|
|
}
|
|
}
|