r2mods/ilspy_dump/ror2_csproj/RoR2/BossGroup.cs

407 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using EntityStates;
using HG;
using RoR2.UI;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2;
[RequireComponent(typeof(CombatSquad))]
public class BossGroup : MonoBehaviour
{
private struct BossMemory
{
public NetworkInstanceId masterInstanceId;
public float maxObservedMaxHealth;
public float lastObservedHealth;
public CharacterMaster cachedMaster;
public CharacterBody cachedBody;
}
private class DefeatBossObjectiveTracker : ObjectivePanelController.ObjectiveTracker
{
public DefeatBossObjectiveTracker()
{
baseToken = "OBJECTIVE_DEFEAT_BOSS";
}
}
public class EnableHudHealthBarState : EntityState
{
private BossGroup bossGroup;
public override void OnEnter()
{
base.OnEnter();
bossGroup = GetComponent<BossGroup>();
if ((object)bossGroup != null)
{
bossGroup.shouldDisplayHealthBarOnHud = true;
}
}
public override void OnExit()
{
if ((object)bossGroup != null)
{
bossGroup.shouldDisplayHealthBarOnHud = false;
}
base.OnExit();
}
}
public float bossDropChance = 0.15f;
public Transform dropPosition;
public PickupDropTable dropTable;
public bool scaleRewardsByPlayerCount = true;
[Tooltip("Whether or not this boss group should display a health bar on the HUD while any of its members are alive. Other scripts can change this at runtime to suppress a health bar until the boss is angered, for example. This field is not networked, so whatever is driving the value should be synchronized over the network.")]
public bool shouldDisplayHealthBarOnHud = true;
private Xoroshiro128Plus rng;
private List<PickupDropTable> bossDropTables;
private Run.FixedTimeStamp enabledTime;
[Header("Deprecated")]
public bool forceTier3Reward;
private List<PickupIndex> bossDrops;
private static readonly int initialBossMemoryCapacity = 8;
private BossMemory[] bossMemories = new BossMemory[initialBossMemoryCapacity];
private int bossMemoryCount;
private static int lastTotalBossCount = 0;
private static bool totalBossCountDirty = false;
public float fixedAge => combatSquad.awakeTime.timeSince;
public float fixedTimeSinceEnabled => enabledTime.timeSince;
public int bonusRewardCount { get; set; }
public CombatSquad combatSquad { get; private set; }
public string bestObservedName { get; private set; } = "";
public string bestObservedSubtitle { get; private set; } = "";
public float totalMaxObservedMaxHealth { get; private set; }
public float totalObservedHealth { get; private set; }
public static event Action<BossGroup> onBossGroupStartServer;
public static event Action<BossGroup> onBossGroupDefeatedServer;
private void Awake()
{
base.enabled = false;
combatSquad = GetComponent<CombatSquad>();
combatSquad.onMemberDiscovered += OnMemberDiscovered;
combatSquad.onMemberLost += OnMemberLost;
if (NetworkServer.active)
{
combatSquad.onDefeatedServer += OnDefeatedServer;
combatSquad.onMemberAddedServer += OnMemberAddedServer;
combatSquad.onMemberDefeatedServer += OnMemberDefeatedServer;
rng = new Xoroshiro128Plus(Run.instance.bossRewardRng.nextUlong);
bossDrops = new List<PickupIndex>();
bossDropTables = new List<PickupDropTable>();
}
}
private void Start()
{
if (NetworkServer.active)
{
BossGroup.onBossGroupStartServer?.Invoke(this);
}
}
private void OnEnable()
{
InstanceTracker.Add(this);
ObjectivePanelController.collectObjectiveSources += ReportObjective;
enabledTime = Run.FixedTimeStamp.now;
}
private void OnDisable()
{
ObjectivePanelController.collectObjectiveSources -= ReportObjective;
InstanceTracker.Remove(this);
}
private void FixedUpdate()
{
UpdateBossMemories();
}
private void OnDefeatedServer()
{
DropRewards();
Run.instance.OnServerBossDefeated(this);
BossGroup.onBossGroupDefeatedServer?.Invoke(this);
}
private void OnMemberAddedServer(CharacterMaster memberMaster)
{
Run.instance.OnServerBossAdded(this, memberMaster);
}
private void OnMemberDefeatedServer(CharacterMaster memberMaster, DamageReport damageReport)
{
DeathRewards deathRewards = memberMaster.GetBodyObject()?.GetComponent<DeathRewards>();
if (!deathRewards)
{
return;
}
if ((bool)deathRewards.bossDropTable)
{
bossDropTables.Add(deathRewards.bossDropTable);
return;
}
PickupIndex pickupIndex = (PickupIndex)deathRewards.bossPickup;
if (pickupIndex != PickupIndex.none)
{
bossDrops.Add(pickupIndex);
}
}
private void OnMemberDiscovered(CharacterMaster memberMaster)
{
base.enabled = true;
memberMaster.isBoss = true;
totalBossCountDirty = true;
RememberBoss(memberMaster);
}
private void OnMemberLost(CharacterMaster memberMaster)
{
memberMaster.isBoss = false;
totalBossCountDirty = true;
if (combatSquad.memberCount == 0)
{
base.enabled = false;
}
}
private void DropRewards()
{
if (!Run.instance)
{
Debug.LogError("No valid run instance!");
return;
}
if (rng == null)
{
Debug.LogError("RNG is null!");
return;
}
int participatingPlayerCount = Run.instance.participatingPlayerCount;
if (participatingPlayerCount == 0)
{
return;
}
if ((bool)dropPosition)
{
PickupIndex none = PickupIndex.none;
if ((bool)dropTable)
{
none = dropTable.GenerateDrop(rng);
}
else
{
List<PickupIndex> list = Run.instance.availableTier2DropList;
if (forceTier3Reward)
{
list = Run.instance.availableTier3DropList;
}
none = rng.NextElementUniform(list);
}
int num = 1 + bonusRewardCount;
if (scaleRewardsByPlayerCount)
{
num *= participatingPlayerCount;
}
float angle = 360f / (float)num;
Vector3 vector = Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), Vector3.up) * (Vector3.up * 40f + Vector3.forward * 5f);
Quaternion quaternion = Quaternion.AngleAxis(angle, Vector3.up);
bool flag = bossDrops != null && bossDrops.Count > 0;
bool flag2 = bossDropTables != null && bossDropTables.Count > 0;
int num2 = 0;
while (num2 < num)
{
PickupIndex pickupIndex = none;
if (bossDrops != null && (flag || flag2) && rng.nextNormalizedFloat <= bossDropChance)
{
if (flag2)
{
PickupDropTable pickupDropTable = rng.NextElementUniform(bossDropTables);
if (pickupDropTable != null)
{
pickupIndex = pickupDropTable.GenerateDrop(rng);
}
}
else
{
pickupIndex = rng.NextElementUniform(bossDrops);
}
}
PickupDropletController.CreatePickupDroplet(pickupIndex, dropPosition.position, vector);
num2++;
vector = quaternion * vector;
}
}
else
{
Debug.LogWarning("dropPosition not set for BossGroup! No item will be spawned.");
}
}
private int FindBossMemoryIndex(NetworkInstanceId id)
{
for (int i = 0; i < bossMemoryCount; i++)
{
if (bossMemories[i].masterInstanceId == id)
{
return i;
}
}
return -1;
}
private void RememberBoss(CharacterMaster master)
{
if ((bool)master)
{
int num = FindBossMemoryIndex(master.netId);
if (num == -1)
{
num = AddBossMemory(master);
}
ref BossMemory reference = ref bossMemories[num];
reference.cachedMaster = master;
reference.cachedBody = master.GetBody();
UpdateObservations(ref reference);
}
}
private void UpdateObservations(ref BossMemory memory)
{
memory.lastObservedHealth = 0f;
if ((bool)memory.cachedMaster && !memory.cachedBody)
{
memory.cachedBody = memory.cachedMaster.GetBody();
}
if (!memory.cachedBody)
{
return;
}
if (bestObservedName.Length == 0 && bestObservedSubtitle.Length == 0 && Time.fixedDeltaTime * 3f < memory.cachedBody.localStartTime.timeSince)
{
bestObservedName = Util.GetBestBodyName(memory.cachedBody.gameObject);
bestObservedSubtitle = memory.cachedBody.GetSubtitle();
if (bestObservedSubtitle.Length == 0)
{
bestObservedSubtitle = Language.GetString("NULL_SUBTITLE");
}
bestObservedSubtitle = "<sprite name=\"CloudLeft\" tint=1> " + bestObservedSubtitle + "<sprite name=\"CloudRight\" tint=1>";
}
HealthComponent healthComponent = memory.cachedBody.healthComponent;
memory.maxObservedMaxHealth = Mathf.Max(memory.maxObservedMaxHealth, healthComponent.fullCombinedHealth);
memory.lastObservedHealth = healthComponent.combinedHealth;
}
private int AddBossMemory(CharacterMaster master)
{
BossMemory bossMemory = default(BossMemory);
bossMemory.masterInstanceId = master.netId;
bossMemory.maxObservedMaxHealth = 0f;
bossMemory.cachedMaster = master;
BossMemory value = bossMemory;
ArrayUtils.ArrayAppend(ref bossMemories, ref bossMemoryCount, in value);
return bossMemoryCount - 1;
}
private void UpdateBossMemories()
{
totalMaxObservedMaxHealth = 0f;
totalObservedHealth = 0f;
for (int i = 0; i < bossMemoryCount; i++)
{
ref BossMemory reference = ref bossMemories[i];
UpdateObservations(ref reference);
totalMaxObservedMaxHealth += reference.maxObservedMaxHealth;
totalObservedHealth += Mathf.Max(reference.lastObservedHealth, 0f);
}
}
public static int GetTotalBossCount()
{
if (totalBossCountDirty)
{
totalBossCountDirty = false;
lastTotalBossCount = 0;
List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
for (int i = 0; i < instancesList.Count; i++)
{
lastTotalBossCount += instancesList[i].combatSquad.readOnlyMembersList.Count;
}
}
return lastTotalBossCount;
}
public static BossGroup FindBossGroup(CharacterBody body)
{
if (!body || !body.isBoss)
{
return null;
}
CharacterMaster master = body.master;
if (!master)
{
return null;
}
List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
for (int i = 0; i < instancesList.Count; i++)
{
BossGroup bossGroup = instancesList[i];
if (bossGroup.combatSquad.ContainsMember(master))
{
return bossGroup;
}
}
return null;
}
public void ReportObjective(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> output)
{
if (combatSquad.readOnlyMembersList.Count != 0)
{
output.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
{
source = this,
master = master,
objectiveType = typeof(DefeatBossObjectiveTracker)
});
}
}
}