using System; using JetBrains.Annotations; using UnityEngine; using UnityEngine.Serialization; namespace RoR2; [CreateAssetMenu(menuName = "RoR2/SpawnCards/CharacterSpawnCard")] public class CharacterSpawnCard : SpawnCard, MasterSummon.IInventorySetupCallback { public bool noElites; public bool forbiddenAsBoss; [CanBeNull] [Tooltip("The loadout for any summoned character to use.")] [FormerlySerializedAs("loadout")] [SerializeField] private SerializableLoadout _loadout; [CanBeNull] [Tooltip("The inventory from which to initially paste into any summoned character's inventory. Will skip certain non-bequeathable items. This is usually not a good idea to set up in the editor, and is more reserved for runtime.")] public Inventory inventoryToCopy; [CanBeNull] public Func inventoryItemCopyFilter; [Tooltip("The set of equipment to grant to any summoned character, after inventory copy.")] [NotNull] public EquipmentDef[] equipmentToGrant = Array.Empty(); [Tooltip("The set of items to grant to any summoned character, after inventory copy.")] [NotNull] public ItemCountPair[] itemsToGrant = Array.Empty(); [CanBeNull] protected Loadout runtimeLoadout; private static ResourceAvailability loadoutAvailability; [CanBeNull] public SerializableLoadout loadout { get { return _loadout; } set { if (_loadout != value) { _loadout = value; if (loadoutAvailability.available) { SetLoadoutFromSerializedLoadout(); } else { loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout); } } } } public void Awake() { if (!loadoutAvailability.available) { loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout); } else { SetLoadoutFromSerializedLoadout(); } } private void SetLoadoutFromSerializedLoadout() { SetLoadout(loadout); } private void SetLoadout([CanBeNull] SerializableLoadout serializableLoadout) { if (Application.isPlaying) { runtimeLoadout = ((serializableLoadout != null && !serializableLoadout.isEmpty) ? new Loadout() : null); if (runtimeLoadout != null) { serializableLoadout.Apply(runtimeLoadout); } } } [CanBeNull] protected virtual Loadout GetRuntimeLoadout() { return runtimeLoadout; } [CanBeNull] protected virtual Action GetPreSpawnSetupCallback() { return null; } protected override void Spawn(Vector3 position, Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result) { MasterSummon masterSummon = new MasterSummon { masterPrefab = prefab, position = position, rotation = rotation, summonerBodyObject = directorSpawnRequest.summonerBodyObject, teamIndexOverride = directorSpawnRequest.teamIndexOverride, ignoreTeamMemberLimit = directorSpawnRequest.ignoreTeamMemberLimit, loadout = GetRuntimeLoadout(), inventoryToCopy = inventoryToCopy, inventoryItemCopyFilter = inventoryItemCopyFilter, inventorySetupCallback = this, preSpawnSetupCallback = GetPreSpawnSetupCallback(), useAmbientLevel = true }; result.spawnedInstance = masterSummon.Perform()?.gameObject; result.success = result.spawnedInstance; } [SystemInitializer(new Type[] { typeof(Loadout) })] private static void Init() { loadoutAvailability.MakeAvailable(); } void MasterSummon.IInventorySetupCallback.SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory) { SetupSummonedInventory(masterSummon, summonedInventory); } protected virtual void SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory) { for (int i = 0; i < equipmentToGrant.Length; i++) { EquipmentState equipment = summonedInventory.GetEquipment((uint)i); summonedInventory.SetEquipment(new EquipmentState(equipmentToGrant[i]?.equipmentIndex ?? EquipmentIndex.None, equipment.chargeFinishTime, equipment.charges), (uint)i); } for (int j = 0; j < itemsToGrant.Length; j++) { ItemCountPair itemCountPair = itemsToGrant[j]; summonedInventory.GiveItem(itemCountPair.itemDef, itemCountPair.count); } } public void OnValidate() { if (occupyPosition) { Debug.LogErrorFormat("{0} OccupyPosition=1.This is only intended for limited spawns, and will prevent spawning on this node in the future! Are ya sure? ", this); } } }