679 lines
18 KiB
C#
679 lines
18 KiB
C#
|
using System;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using RoR2.Navigation;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Networking;
|
||
|
|
||
|
namespace RoR2;
|
||
|
|
||
|
public class InfiniteTowerRun : Run
|
||
|
{
|
||
|
[Serializable]
|
||
|
public struct EnemyItemEntry
|
||
|
{
|
||
|
public PickupDropTable dropTable;
|
||
|
|
||
|
public int stacks;
|
||
|
}
|
||
|
|
||
|
private const ulong waveRngSalt = 14312uL;
|
||
|
|
||
|
private const ulong enemyItemRngSalt = 1535uL;
|
||
|
|
||
|
private const ulong safeWardRngSalt = 769876uL;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Header("Infinite Tower Settings")]
|
||
|
[Tooltip("If all else fails, use this wave prefab")]
|
||
|
private GameObject defaultWavePrefab;
|
||
|
|
||
|
[Tooltip("Selects a wave from the first available category in this list")]
|
||
|
[SerializeField]
|
||
|
private InfiniteTowerWaveCategory[] waveCategories;
|
||
|
|
||
|
[Tooltip("Use this indicator for enemies by default")]
|
||
|
[SerializeField]
|
||
|
private GameObject defaultWaveEnemyIndicatorPrefab;
|
||
|
|
||
|
[Tooltip("The repeating pattern of drop tables to use when selecting items for the enemy team")]
|
||
|
[SerializeField]
|
||
|
private EnemyItemEntry[] enemyItemPattern;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Tooltip("The number of waves before you give the enemy team the next item in the pattern (e.g., \"every Nth wave\")")]
|
||
|
private int enemyItemPeriod;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Tooltip("The reference inventory we use to store which items enemies should get")]
|
||
|
private Inventory enemyInventory;
|
||
|
|
||
|
[Tooltip("The number of waves before you transition to the next stage (e.g., \"every Nth wave\").")]
|
||
|
[SerializeField]
|
||
|
private int stageTransitionPeriod;
|
||
|
|
||
|
[Tooltip("Spawn card for the stage transition portal")]
|
||
|
[SerializeField]
|
||
|
private InteractableSpawnCard stageTransitionPortalCard;
|
||
|
|
||
|
[Tooltip("Maximum spawn distance for the stage transition portal.")]
|
||
|
[SerializeField]
|
||
|
private float stageTransitionPortalMaxDistance;
|
||
|
|
||
|
[Tooltip("The chat message that's broadcasted when spawning the stage transition portal.")]
|
||
|
[SerializeField]
|
||
|
private string stageTransitionChatToken;
|
||
|
|
||
|
[Tooltip("The prefab with the FogDamageController attached")]
|
||
|
[SerializeField]
|
||
|
private GameObject fogDamagePrefab;
|
||
|
|
||
|
[SerializeField]
|
||
|
[Tooltip("The maximum distance to spawn players from the safe ward")]
|
||
|
private float spawnMaxRadius;
|
||
|
|
||
|
[Tooltip("Spawn card for the safe ward that is spawned at the beginning of the run")]
|
||
|
[SerializeField]
|
||
|
private InteractableSpawnCard initialSafeWardCard;
|
||
|
|
||
|
[Tooltip("Spawn card for the safe wards (after the first one)")]
|
||
|
[SerializeField]
|
||
|
private InteractableSpawnCard safeWardCard;
|
||
|
|
||
|
[Tooltip("The effect to spawn when a player is revived at the end of a wave")]
|
||
|
[SerializeField]
|
||
|
private GameObject playerRespawnEffectPrefab;
|
||
|
|
||
|
[Tooltip("The number of credits the SceneDirector uses to spawn interactables")]
|
||
|
[SerializeField]
|
||
|
private int interactableCredits;
|
||
|
|
||
|
[Tooltip("Remove all items with these tags from the item pools")]
|
||
|
[SerializeField]
|
||
|
private ItemTag[] blacklistedTags;
|
||
|
|
||
|
[Tooltip("Remove these items from the pool")]
|
||
|
[SerializeField]
|
||
|
private ItemDef[] blacklistedItems;
|
||
|
|
||
|
[SyncVar]
|
||
|
private int _waveIndex;
|
||
|
|
||
|
[SyncVar]
|
||
|
private NetworkInstanceId waveInstanceId;
|
||
|
|
||
|
private InfiniteTowerWaveController _waveController;
|
||
|
|
||
|
private Xoroshiro128Plus waveRng;
|
||
|
|
||
|
private Xoroshiro128Plus enemyItemRng;
|
||
|
|
||
|
private Xoroshiro128Plus safeWardRng;
|
||
|
|
||
|
private int enemyItemPatternIndex;
|
||
|
|
||
|
private InfiniteTowerSafeWardController safeWardController;
|
||
|
|
||
|
private FogDamageController fogDamageController;
|
||
|
|
||
|
public int waveIndex => _waveIndex;
|
||
|
|
||
|
public InfiniteTowerWaveController waveController => _waveController;
|
||
|
|
||
|
public override bool spawnWithPod => false;
|
||
|
|
||
|
public override bool canFamilyEventTrigger => false;
|
||
|
|
||
|
public override bool autoGenerateSpawnPoints => false;
|
||
|
|
||
|
public GameObject waveInstance => Util.FindNetworkObject(waveInstanceId);
|
||
|
|
||
|
public int Network_waveIndex
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _waveIndex;
|
||
|
}
|
||
|
[param: In]
|
||
|
set
|
||
|
{
|
||
|
SetSyncVar(value, ref _waveIndex, 64u);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public NetworkInstanceId NetworkwaveInstanceId
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return waveInstanceId;
|
||
|
}
|
||
|
[param: In]
|
||
|
set
|
||
|
{
|
||
|
SetSyncVar(value, ref waveInstanceId, 128u);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static event Action<InfiniteTowerWaveController> onWaveInitialized;
|
||
|
|
||
|
public static event Action<InfiniteTowerWaveController> onAllEnemiesDefeatedServer;
|
||
|
|
||
|
public override GameObject InstantiateUi(Transform uiRoot)
|
||
|
{
|
||
|
GameObject gameObject = base.InstantiateUi(uiRoot);
|
||
|
if ((bool)_waveController)
|
||
|
{
|
||
|
_waveController.InstantiateUi(gameObject.transform);
|
||
|
}
|
||
|
return gameObject;
|
||
|
}
|
||
|
|
||
|
public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed)
|
||
|
{
|
||
|
base.OverrideRuleChoices(mustInclude, mustExclude, base.seed);
|
||
|
ItemIndex itemIndex = ItemIndex.Count;
|
||
|
for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
|
||
|
{
|
||
|
ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
|
||
|
bool flag = Array.IndexOf(blacklistedItems, itemDef) != -1;
|
||
|
if (!flag)
|
||
|
{
|
||
|
ItemTag[] array = blacklistedTags;
|
||
|
foreach (ItemTag itemTag in array)
|
||
|
{
|
||
|
if (itemDef.ContainsTag(itemTag))
|
||
|
{
|
||
|
flag = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (flag)
|
||
|
{
|
||
|
RuleChoiceDef ruleChoiceDef = RuleCatalog.FindRuleDef("Items." + itemDef.name)?.FindChoice("Off");
|
||
|
if (ruleChoiceDef != null)
|
||
|
{
|
||
|
ForceChoice(mustInclude, mustExclude, ruleChoiceDef);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
public void ResetSafeWard()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::ResetSafeWard()' called on client");
|
||
|
return;
|
||
|
}
|
||
|
if ((bool)safeWardController)
|
||
|
{
|
||
|
if ((bool)fogDamageController)
|
||
|
{
|
||
|
fogDamageController.RemoveSafeZone(safeWardController.safeZone);
|
||
|
}
|
||
|
safeWardController.SelfDestruct();
|
||
|
}
|
||
|
SpawnSafeWard(safeWardCard, new DirectorPlacementRule
|
||
|
{
|
||
|
placementMode = DirectorPlacementRule.PlacementMode.Random
|
||
|
});
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
public void MoveSafeWard()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::MoveSafeWard()' called on client");
|
||
|
}
|
||
|
else if ((bool)safeWardController)
|
||
|
{
|
||
|
safeWardController.RandomizeLocation(safeWardRng);
|
||
|
safeWardController.onActivated += OnSafeWardActivated;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsStageTransitionWave()
|
||
|
{
|
||
|
if (stageTransitionPeriod != 0)
|
||
|
{
|
||
|
return waveIndex % stageTransitionPeriod == 0;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination)
|
||
|
{
|
||
|
if ((bool)safeWardController && !targetDestination)
|
||
|
{
|
||
|
return base.FindSafeTeleportPosition(characterBody, safeWardController.transform);
|
||
|
}
|
||
|
return base.FindSafeTeleportPosition(characterBody, targetDestination);
|
||
|
}
|
||
|
|
||
|
public override Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination, float idealMinDistance, float idealMaxDistance)
|
||
|
{
|
||
|
if ((bool)safeWardController && !targetDestination)
|
||
|
{
|
||
|
return base.FindSafeTeleportPosition(characterBody, safeWardController.transform, idealMinDistance, idealMaxDistance);
|
||
|
}
|
||
|
return base.FindSafeTeleportPosition(characterBody, targetDestination, idealMinDistance, idealMaxDistance);
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
private void OnSafeWardActivated(InfiniteTowerSafeWardController safeWard)
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::OnSafeWardActivated(RoR2.InfiniteTowerSafeWardController)' called on client");
|
||
|
return;
|
||
|
}
|
||
|
safeWardController.onActivated -= OnSafeWardActivated;
|
||
|
if ((bool)_waveController)
|
||
|
{
|
||
|
_waveController.ForceFinish();
|
||
|
CleanUpCurrentWave();
|
||
|
}
|
||
|
BeginNextWave();
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
private void AdvanceWave()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::AdvanceWave()' called on client");
|
||
|
return;
|
||
|
}
|
||
|
Network_waveIndex = _waveIndex + 1;
|
||
|
if (_waveIndex % enemyItemPeriod != 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
EnemyItemEntry enemyItemEntry = enemyItemPattern[enemyItemPatternIndex++ % enemyItemPattern.Length];
|
||
|
if (!enemyItemEntry.dropTable)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
PickupIndex pickupIndex = enemyItemEntry.dropTable.GenerateDrop(enemyItemRng);
|
||
|
if (pickupIndex != PickupIndex.none)
|
||
|
{
|
||
|
PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
|
||
|
if (pickupDef != null)
|
||
|
{
|
||
|
enemyInventory.GiveItem(pickupDef.itemIndex, enemyItemEntry.stacks);
|
||
|
Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
|
||
|
{
|
||
|
baseToken = "INFINITETOWER_ADD_ITEM",
|
||
|
pickupToken = pickupDef.nameToken,
|
||
|
pickupColor = pickupDef.baseColor
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
private void BeginNextWave()
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::BeginNextWave()' called on client");
|
||
|
return;
|
||
|
}
|
||
|
AdvanceWave();
|
||
|
GameObject original = defaultWavePrefab;
|
||
|
InfiniteTowerWaveCategory[] array = waveCategories;
|
||
|
foreach (InfiniteTowerWaveCategory infiniteTowerWaveCategory in array)
|
||
|
{
|
||
|
if (infiniteTowerWaveCategory.IsAvailable(this))
|
||
|
{
|
||
|
original = infiniteTowerWaveCategory.SelectWavePrefab(this, waveRng);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
GameObject gameObject = UnityEngine.Object.Instantiate(original, base.transform);
|
||
|
NetworkServer.Spawn(gameObject);
|
||
|
NetworkwaveInstanceId = gameObject.GetComponent<NetworkIdentity>().netId;
|
||
|
RecalculateDifficultyCoefficentInternal();
|
||
|
}
|
||
|
|
||
|
protected override void Start()
|
||
|
{
|
||
|
Stage.onServerStageBegin += OnServerStageBegin;
|
||
|
Stage.onServerStageComplete += OnServerStageComplete;
|
||
|
SceneDirector.onPrePopulateSceneServer += OnPrePopulateSceneServer;
|
||
|
base.Start();
|
||
|
}
|
||
|
|
||
|
protected override void OnDestroy()
|
||
|
{
|
||
|
Stage.onServerStageBegin -= OnServerStageBegin;
|
||
|
Stage.onServerStageComplete -= OnServerStageComplete;
|
||
|
SceneDirector.onPrePopulateSceneServer -= OnPrePopulateSceneServer;
|
||
|
if ((bool)safeWardController)
|
||
|
{
|
||
|
UnityEngine.Object.Destroy(safeWardController.gameObject);
|
||
|
safeWardController = null;
|
||
|
}
|
||
|
CleanUpCurrentWave();
|
||
|
base.OnDestroy();
|
||
|
}
|
||
|
|
||
|
private void OnServerStageBegin(Stage stage)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
private void OnServerStageComplete(Stage stage)
|
||
|
{
|
||
|
PerformStageCleanUp();
|
||
|
}
|
||
|
|
||
|
private void OnPrePopulateSceneServer(SceneDirector sceneDirector)
|
||
|
{
|
||
|
PerformStageCleanUp();
|
||
|
if ((bool)fogDamagePrefab)
|
||
|
{
|
||
|
GameObject gameObject = UnityEngine.Object.Instantiate(fogDamagePrefab, Stage.instance.transform);
|
||
|
NetworkServer.Spawn(gameObject);
|
||
|
fogDamageController = gameObject.GetComponent<FogDamageController>();
|
||
|
}
|
||
|
sceneDirector.interactableCredit = interactableCredits;
|
||
|
DirectorPlacementRule placementRule = new DirectorPlacementRule
|
||
|
{
|
||
|
placementMode = DirectorPlacementRule.PlacementMode.Random
|
||
|
};
|
||
|
SpawnSafeWard(initialSafeWardCard, placementRule);
|
||
|
if (!safeWardController)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
Vector3 position = safeWardController.transform.position;
|
||
|
NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
|
||
|
foreach (NodeGraph.NodeIndex item in nodeGraph.FindNodesInRangeWithFlagConditions(position, 0f, spawnMaxRadius, HullMask.Human, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false))
|
||
|
{
|
||
|
if (nodeGraph.GetNodePosition(item, out var position2))
|
||
|
{
|
||
|
SpawnPoint.AddSpawnPoint(position2, Quaternion.LookRotation(position, Vector3.up));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override void FixedUpdate()
|
||
|
{
|
||
|
base.FixedUpdate();
|
||
|
if (NetworkServer.active && (bool)waveInstance && (bool)waveController && waveController.isFinished && !IsStageTransitionWave())
|
||
|
{
|
||
|
CleanUpCurrentWave();
|
||
|
BeginNextWave();
|
||
|
}
|
||
|
if ((bool)waveInstance)
|
||
|
{
|
||
|
if (!_waveController)
|
||
|
{
|
||
|
InitializeWaveController();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_waveController = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override void RecalculateDifficultyCoefficentInternal()
|
||
|
{
|
||
|
DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(base.selectedDifficulty);
|
||
|
float num = 1.5f * (float)waveIndex;
|
||
|
float num2 = 0.0506f * difficultyDef.scalingValue;
|
||
|
float num3 = Mathf.Pow(1.02f, waveIndex);
|
||
|
difficultyCoefficient = (1f + num2 * num) * num3;
|
||
|
compensatedDifficultyCoefficient = difficultyCoefficient;
|
||
|
base.ambientLevel = Mathf.Min((difficultyCoefficient - 1f) / 0.33f + 1f, 9999f);
|
||
|
int num4 = base.ambientLevelFloor;
|
||
|
base.ambientLevelFloor = Mathf.FloorToInt(base.ambientLevel);
|
||
|
if (num4 != base.ambientLevelFloor && num4 != 0 && base.ambientLevelFloor > num4)
|
||
|
{
|
||
|
OnAmbientLevelUp();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void InitializeWaveController()
|
||
|
{
|
||
|
_waveController = waveInstance.GetComponent<InfiniteTowerWaveController>();
|
||
|
if (!_waveController)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (NetworkServer.active)
|
||
|
{
|
||
|
_waveController.Initialize(_waveIndex, enemyInventory, safeWardController.gameObject);
|
||
|
}
|
||
|
foreach (GameObject uiInstance in base.uiInstances)
|
||
|
{
|
||
|
_waveController.InstantiateUi(uiInstance.transform);
|
||
|
}
|
||
|
_waveController.PlayBeginSound();
|
||
|
_waveController.defaultEnemyIndicatorPrefab = defaultWaveEnemyIndicatorPrefab;
|
||
|
_waveController.onAllEnemiesDefeatedServer += OnWaveAllEnemiesDefeatedServer;
|
||
|
InfiniteTowerRun.onWaveInitialized?.Invoke(_waveController);
|
||
|
}
|
||
|
|
||
|
private void OnWaveAllEnemiesDefeatedServer(InfiniteTowerWaveController wc)
|
||
|
{
|
||
|
InfiniteTowerRun.onAllEnemiesDefeatedServer?.Invoke(wc);
|
||
|
if (base.isGameOverServer)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
|
||
|
{
|
||
|
CharacterMaster master = instance.master;
|
||
|
if (!instance.isConnected || !master.IsDeadAndOutOfLivesServer())
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
Vector3 vector = master.deathFootPosition;
|
||
|
if ((bool)safeWardController)
|
||
|
{
|
||
|
vector = TeleportHelper.FindSafeTeleportDestination(safeWardController.transform.position, master.bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? vector;
|
||
|
}
|
||
|
master.Respawn(vector, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f));
|
||
|
CharacterBody body = master.GetBody();
|
||
|
if ((bool)body)
|
||
|
{
|
||
|
body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
|
||
|
EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
|
||
|
foreach (EntityStateMachine obj in components)
|
||
|
{
|
||
|
obj.initialStateType = obj.mainStateType;
|
||
|
}
|
||
|
if ((bool)playerRespawnEffectPrefab)
|
||
|
{
|
||
|
EffectManager.SpawnEffect(playerRespawnEffectPrefab, new EffectData
|
||
|
{
|
||
|
origin = vector,
|
||
|
rotation = body.transform.rotation
|
||
|
}, transmit: true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (IsStageTransitionWave())
|
||
|
{
|
||
|
PickNextStageSceneFromCurrentSceneDestinations();
|
||
|
DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(stageTransitionPortalCard, new DirectorPlacementRule
|
||
|
{
|
||
|
minDistance = 0f,
|
||
|
maxDistance = stageTransitionPortalMaxDistance,
|
||
|
placementMode = DirectorPlacementRule.PlacementMode.Approximate,
|
||
|
position = safeWardController.transform.position,
|
||
|
spawnOnTarget = safeWardController.transform
|
||
|
}, safeWardRng));
|
||
|
Chat.SendBroadcastChat(new Chat.SimpleChatMessage
|
||
|
{
|
||
|
baseToken = stageTransitionChatToken
|
||
|
});
|
||
|
if ((bool)safeWardController)
|
||
|
{
|
||
|
safeWardController.WaitForPortal();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override bool ShouldUpdateRunStopwatch()
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
protected override void OnSeedSet()
|
||
|
{
|
||
|
waveRng = new Xoroshiro128Plus(base.seed ^ 0x37E8);
|
||
|
enemyItemRng = new Xoroshiro128Plus(base.seed ^ 0x5FF);
|
||
|
safeWardRng = new Xoroshiro128Plus(base.seed ^ 0xBBF54);
|
||
|
}
|
||
|
|
||
|
private void CleanUpCurrentWave()
|
||
|
{
|
||
|
if ((bool)_waveController)
|
||
|
{
|
||
|
_waveController.onAllEnemiesDefeatedServer -= OnWaveAllEnemiesDefeatedServer;
|
||
|
_waveController = null;
|
||
|
}
|
||
|
if ((bool)waveInstance)
|
||
|
{
|
||
|
UnityEngine.Object.Destroy(waveInstance);
|
||
|
}
|
||
|
NetworkwaveInstanceId = NetworkInstanceId.Invalid;
|
||
|
}
|
||
|
|
||
|
private void SpawnSafeWard(InteractableSpawnCard spawnCard, DirectorPlacementRule placementRule)
|
||
|
{
|
||
|
GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, safeWardRng));
|
||
|
if ((bool)gameObject)
|
||
|
{
|
||
|
NetworkServer.Spawn(gameObject);
|
||
|
safeWardController = gameObject.GetComponent<InfiniteTowerSafeWardController>();
|
||
|
if ((bool)safeWardController)
|
||
|
{
|
||
|
safeWardController.onActivated += OnSafeWardActivated;
|
||
|
}
|
||
|
HoldoutZoneController component = gameObject.GetComponent<HoldoutZoneController>();
|
||
|
if ((bool)component)
|
||
|
{
|
||
|
component.calcAccumulatedCharge += CalcHoldoutZoneCharge;
|
||
|
}
|
||
|
if ((bool)fogDamageController)
|
||
|
{
|
||
|
fogDamageController.AddSafeZone(safeWardController.safeZone);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogError("Unable to spawn safe ward instance. Are there any ground nodes?");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CalcHoldoutZoneCharge(ref float charge)
|
||
|
{
|
||
|
if ((bool)waveController)
|
||
|
{
|
||
|
float num = waveController.GetNormalizedProgress();
|
||
|
if (waveController.GetSquadCount() > 0)
|
||
|
{
|
||
|
num = Mathf.Min(num, 0.99f);
|
||
|
}
|
||
|
charge = num;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
charge = 0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Server]
|
||
|
public override void HandlePlayerFirstEntryAnimation(CharacterBody body, Vector3 spawnPosition, Quaternion spawnRotation)
|
||
|
{
|
||
|
if (!NetworkServer.active)
|
||
|
{
|
||
|
Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::HandlePlayerFirstEntryAnimation(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
body.SetBodyStateToPreferredInitialState();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void PerformStageCleanUp()
|
||
|
{
|
||
|
safeWardController = null;
|
||
|
if ((bool)fogDamageController)
|
||
|
{
|
||
|
UnityEngine.Object.Destroy(fogDamageController.gameObject);
|
||
|
}
|
||
|
CleanUpCurrentWave();
|
||
|
}
|
||
|
|
||
|
private void UNetVersion()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
|
||
|
{
|
||
|
bool flag = base.OnSerialize(writer, forceAll);
|
||
|
if (forceAll)
|
||
|
{
|
||
|
writer.WritePackedUInt32((uint)_waveIndex);
|
||
|
writer.Write(waveInstanceId);
|
||
|
return true;
|
||
|
}
|
||
|
bool flag2 = false;
|
||
|
if ((base.syncVarDirtyBits & 0x40u) != 0)
|
||
|
{
|
||
|
if (!flag2)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
flag2 = true;
|
||
|
}
|
||
|
writer.WritePackedUInt32((uint)_waveIndex);
|
||
|
}
|
||
|
if ((base.syncVarDirtyBits & 0x80u) != 0)
|
||
|
{
|
||
|
if (!flag2)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
flag2 = true;
|
||
|
}
|
||
|
writer.Write(waveInstanceId);
|
||
|
}
|
||
|
if (!flag2)
|
||
|
{
|
||
|
writer.WritePackedUInt32(base.syncVarDirtyBits);
|
||
|
}
|
||
|
return flag2 || flag;
|
||
|
}
|
||
|
|
||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||
|
{
|
||
|
base.OnDeserialize(reader, initialState);
|
||
|
if (initialState)
|
||
|
{
|
||
|
_waveIndex = (int)reader.ReadPackedUInt32();
|
||
|
waveInstanceId = reader.ReadNetworkId();
|
||
|
return;
|
||
|
}
|
||
|
int num = (int)reader.ReadPackedUInt32();
|
||
|
if (((uint)num & 0x40u) != 0)
|
||
|
{
|
||
|
_waveIndex = (int)reader.ReadPackedUInt32();
|
||
|
}
|
||
|
if (((uint)num & 0x80u) != 0)
|
||
|
{
|
||
|
waveInstanceId = reader.ReadNetworkId();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void PreStartClient()
|
||
|
{
|
||
|
base.PreStartClient();
|
||
|
}
|
||
|
}
|