Пример #1
0
    /// <summary>
    /// Mage player's secondary attack
    /// </summary>
    protected override void SecondaryAttack()
    {
        // Ensure player has enough mana to perform this attack
        if (AttackCooldown > 0 || (Stats as PlayerStatsController).mana.CurrentValue < secondaryAttackManaDepletion)
        {
            return;
        }

        StartCoroutine(VfxHelper.CreateVFX(secondaryVFX, transform.position + new Vector3(0, 0.01f, 0), Quaternion.identity, PlayerManager.colours.GetColour(Stats.characterColour)));

        // Check all enemies within attack radius of the player
        List <Transform> enemies = GetSurroundingEnemies(secondaryAttackRadius);

        // Attack any enemies within the AOE range
        foreach (var enemy in enemies)
        {
            StartCoroutine(PerformExplosiveDamage(enemy.GetComponent <EntityStatsController>(),
                                                  secondaryAttackMaxDamage, secondaryAttackStunTime, secondaryAttackExplosionForce,
                                                  transform.position, secondaryAttackRadius, secondaryAttackDamageDelay));
        }

        // Trigger secondary attack animation
        Anim.SetTrigger("SecondaryAttack");

        // Play the attack audio
        StartCoroutine(AudioHelper.PlayAudioOverlap(WeaponAudio, secondaryAttackWeaponSFX));

        // Reset attack timeout and deplete mana
        AttackCooldown = secondaryAttackTimeout;
        (Stats as PlayerStatsController).mana.Subtract(secondaryAttackManaDepletion);

        // Apply movement speed modifier
        StartCoroutine(Motor.ApplyTimedMovementModifier(secondaryAttackMovementModifier, secondaryAttackTimeout));
    }
    /// <summary>
    /// Lich's spell cast attack
    /// </summary>
    public override void SecondaryAttack()
    {
        // Calculate direction to attack in relative to staff position
        Vector3 direction = secondaryAttackVFXRoot.up;

        direction.y = 0f;
        Vector3 position = secondaryAttackVFXRoot.position;

        position.y = 1f;

        // Spawn VFX from staff and in the direction its pointing
        Vector3 vfxPos = position + direction * 0.5f + new Vector3(0, 2f);

        StartCoroutine(VfxHelper.CreateVFX(secondaryAttackVFX, vfxPos, Quaternion.LookRotation(direction)));

        // Calculate the hit raycast from closer to the enemy, in the direction of the staff
        Vector3 raycastPos  = position - direction * 2.5f;
        int     numHits     = Physics.RaycastNonAlloc(raycastPos, direction, _hitBuffer, secondaryAttackRadius);
        float   damageValue = Random.Range(secondaryAttackMinDamage, secondaryAttackMaxDamage) + Stats.damage.GetValue();

        // Damage any players hit by the raycast
        for (int i = 0; i < numHits; i++)
        {
            if (_hitBuffer[i].transform.tag.Equals("Player"))
            {
                _hitBuffer[i].transform.GetComponent <EntityStatsController>().TakeDamage(Stats, damageValue, Time.deltaTime);
            }
        }
    }
        public static void Postfix(CombatHUDStatusPanel __instance, List <CombatHUDStatusIndicator> ___Buffs, List <CombatHUDStatusIndicator> ___Debuffs)
        {
            Mod.Log.Trace?.Write("CHUDSP:RDC - entered.");
            if (__instance != null && __instance.DisplayedCombatant != null)
            {
                AbstractActor target = __instance.DisplayedCombatant as AbstractActor;
                // We can receive a building here, so
                if (target != null)
                {
                    if (target.Combat.HostilityMatrix.IsLocalPlayerEnemy(target.team))
                    {
                        SensorScanType scanType = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated);

                        // Hide the buffs and debuffs if the current scanType is less than allInfo
                        if (scanType < SensorScanType.AllInformation)
                        {
                            //// Hide the buffs and debuffs
                            ___Buffs.ForEach(si => si.gameObject.SetActive(false));
                            ___Debuffs.ForEach(si => si.gameObject.SetActive(false));
                        }
                    }

                    // Calculate stealth pips
                    Traverse stealthDisplayT = Traverse.Create(__instance).Field("stealthDisplay");
                    CombatHUDStealthBarPips stealthDisplay = stealthDisplayT.GetValue <CombatHUDStealthBarPips>();
                    VfxHelper.CalculateMimeticPips(stealthDisplay, target);
                }
            }
        }
Пример #4
0
        public static void Postfix(MechComponent __instance, bool __state)
        {
            Mod.Log.Trace?.Write("MC:CCE:post entered.");

            if (__state)
            {
                Mod.Log.Debug?.Write($" Stealth effect was cancelled, parent visibility needs refreshed.");

                EWState parentState = new EWState(__instance.parent);
                PilotableActorRepresentation par = __instance.parent.GameRep as PilotableActorRepresentation;
                if (parentState.HasStealth())
                {
                    VfxHelper.EnableStealthVfx(__instance.parent);
                }
                else
                {
                    VfxHelper.DisableSensorStealthEffect(__instance.parent);
                }

                if (parentState.HasMimetic())
                {
                    VfxHelper.EnableMimeticEffect(__instance.parent);
                }
                else
                {
                    VfxHelper.DisableMimeticEffect(__instance.parent);
                }

                // Force a refresh in case the signature increased due to stealth loss
                // TODO: Make this player hostile only
                List <ICombatant> allLivingCombatants = __instance.parent.Combat.GetAllLivingCombatants();
                __instance.parent.VisibilityCache.UpdateCacheReciprocal(allLivingCombatants);
            }
        }
Пример #5
0
    /// <summary>
    /// Melee's secondary attack
    /// </summary>
    protected override void SecondaryAttack()
    {
        // Ensure player has enough mana to perform this attack
        if (AttackCooldown > 0 || (Stats as PlayerStatsController).mana.CurrentValue < secondaryAttackManaDepletion)
        {
            return;
        }

        StartCoroutine(VfxHelper.CreateVFX(secondaryVFX, transform.position + new Vector3(0, 0.01f, 0), transform.rotation,
                                           PlayerManager.colours.GetColour(Stats.characterColour), secondaryAttackDamageDelay));

        // Check all enemies within attack radius of the player
        List <Transform> enemies = GetSurroundingEnemies(secondaryAttackRadius);

        // Attack any enemies within the attack sweep and range
        foreach (var enemy in enemies.Where(enemy => CanDamageTarget(enemy, secondaryAttackRadius, secondaryAttackSweepAngle)))
        {
            // Calculate and perform damage
            float damageValue = Random.Range(secondaryAttackMinDamage, secondaryAttackMaxDamage + Stats.damage.GetValue());
            StartCoroutine(PerformDamage(enemy.GetComponent <EntityStatsController>(), damageValue, secondaryAttackDamageDelay));
        }

        // Trigger secondary attack animation
        Anim.SetTrigger("SecondaryAttack");

        // Play the attack audio
        StartCoroutine(AudioHelper.PlayAudioOverlap(WeaponAudio, secondaryAttackWeaponSFX));

        // Reset attack timeout and deplete mana
        AttackCooldown = secondaryAttackTimeout;
        (Stats as PlayerStatsController).mana.Subtract(secondaryAttackManaDepletion);

        // Apply movement speed modifier
        StartCoroutine(Motor.ApplyTimedMovementModifier(secondaryAttackMovementModifier, secondaryAttackTimeout));
    }
Пример #6
0
    /// <summary>
    /// Mage player's primary attack
    /// </summary>
    protected override void PrimaryAttack()
    {
        // Ensure player has enough mana to perform this attack
        if ((Stats as PlayerStatsController).mana.CurrentValue < 1f)
        {
            // Stop attack if not enough mana
            ReleaseChargedAttack();
            return;
        }

        (Stats as PlayerStatsController).mana.Subtract(primaryAttackManaDepletion * Time.deltaTime);

        Vector3 vfxPos = transform.position + transform.forward * 1.6f + new Vector3(0, 2f);

        StartCoroutine(VfxHelper.CreateVFX(primaryVFX, vfxPos, transform.rotation));

        // Check all enemies within attack radius of the player
        List <Transform> enemies     = GetSurroundingEnemies(primaryAttackRadius);
        float            baseDamage  = Stats.damage.GetValue();
        float            damageValue = Random.Range(primaryAttackMinDamage + baseDamage, primaryAttackMaxDamage + baseDamage);

        // Attack any enemies within the attack sweep and range
        foreach (var enemy in enemies.Where(enemy => CanDamageTarget(enemy, primaryAttackRadius, primaryAttackSweepAngle)))
        {
            enemy.GetComponent <EntityStatsController>().TakeDamage(Stats, damageValue, Time.deltaTime);
        }
    }
Пример #7
0
    /// <summary>
    /// Mage player's primary attack
    /// </summary>
    protected override void PrimaryAttack()
    {
        // Ensure player has enough mana to perform this attack
        if ((Stats as PlayerStatsController).mana.CurrentValue < 1f)
        {
            // Stop attack if not enough mana
            _isPrimaryActive = false;
            Anim.SetBool("PrimaryAttack", false);
            AudioHelper.StopAudio(WeaponAudio);
            (Stats as PlayerStatsController).mana.StartRegen();
            Motor.ResetMovementModifier();
            return;
        }

        (Stats as PlayerStatsController).mana.Subtract(primaryAttackManaDepletion * Time.deltaTime);

        ResetTakeDamageAnim();
        Vector3 vfxPos = transform.position + transform.forward * 1.5f + new Vector3(0, 2f);

        StartCoroutine(VfxHelper.CreateVFX(primaryVFX, vfxPos, transform.rotation));

        // Check all enemies within attack radius of the player
        List <Transform> enemies = GetSurroundingEnemies(primaryAttackRadius);

        // Attack any enemies within the attack sweep and range
        foreach (var enemy in enemies.Where(enemy => CanDamageTarget(enemy, primaryAttackRadius, primaryAttackSweepAngle)))
        {
            float damageValue = Random.Range(primaryAttackMinDamage, primaryAttackMaxDamage + Stats.damage.GetValue());
            enemy.GetComponent <EntityStatsController>().TakeDamage(Stats, damageValue, Time.deltaTime);
        }
    }
Пример #8
0
        public static void Prefix(TurnDirector __instance)
        {
            Mod.Log.Trace?.Write("TD:OEB:pre entered.");

            // Initialize the probabilities
            ModState.InitializeCheckResults();
            ModState.InitMapConfig();
            ModState.TurnDirectorStarted = true;

            // Do a pre-encounter populate
            if (__instance != null && __instance.Combat != null && __instance.Combat.AllActors != null)
            {
                // If we are coming from a save, don't recalculate everything - just roll with what we already have
                if (!IsFromSave)
                {
                    AbstractActor randomPlayerActor = null;
                    foreach (AbstractActor actor in __instance.Combat.AllActors)
                    {
                        if (actor != null)
                        {
                            // Make a pre-encounter detectCheck for them
                            ActorHelper.UpdateSensorCheck(actor, false);

                            bool isPlayer = actor.TeamId == __instance.Combat.LocalPlayerTeamGuid;
                            if (isPlayer && randomPlayerActor == null)
                            {
                                randomPlayerActor = actor;
                            }
                        }
                        else
                        {
                            Mod.Log.Debug?.Write($"  Actor:{CombatantUtils.Label(actor)} was NULL!");
                        }
                    }

                    if (randomPlayerActor != null)
                    {
                        Mod.Log.Debug?.Write($"Assigning actor: {CombatantUtils.Label(randomPlayerActor)} as lastActive.");
                        ModState.LastPlayerActorActivated = randomPlayerActor;
                    }
                }
            }

            // Initialize the VFX materials
            // TODO: Do a pooled instantiate here?
            VfxHelper.Initialize(__instance.Combat);

            // Attach to the message bus so we get updates on selected actor
            SelectedActorHelper.Combat = __instance.Combat;
            __instance.Combat.MessageCenter.Subscribe(MessageCenterMessageType.ActorSelectedMessage,
                                                      new ReceiveMessageCenterMessage(SelectedActorHelper.OnActorSelectedMessage), true);
            __instance.Combat.MessageCenter.Subscribe(MessageCenterMessageType.OnAuraAdded,
                                                      new ReceiveMessageCenterMessage(SelectedActorHelper.OnAuraAddedMessage), true);
            __instance.Combat.MessageCenter.Subscribe(MessageCenterMessageType.OnAuraRemoved,
                                                      new ReceiveMessageCenterMessage(SelectedActorHelper.OnAuraRemovedMessage), true);
        }
        public static void Postfix(CombatHUDStatusPanel __instance, AbstractActor target, float previewStealth, CombatHUDStealthBarPips ___stealthDisplay)
        {
            if (___stealthDisplay == null)
            {
                return;
            }
            Mod.Log.Trace?.Write("CHUDSP:SSI:float - entered.");

            VfxHelper.CalculateMimeticPips(___stealthDisplay, target);
        }
            public static void Postfix(CombatHUDActorInfo __instance, MessageCenterMessage message, AbstractActor ___displayedActor)
            {
                Mod.Log.Trace?.Write("CHUDAI:OSC entered");

                StealthChangedMessage stealthChangedMessage = message as StealthChangedMessage;

                if (___displayedActor != null && stealthChangedMessage.affectedObjectGuid == ___displayedActor.GUID && __instance.StealthDisplay != null)
                {
                    VfxHelper.CalculateMimeticPips(__instance.StealthDisplay, ___displayedActor);
                }
            }
Пример #11
0
        public static void Prefix(AbstractActor __instance)
        {
            Mod.Log.Trace?.Write("AA:OnAEnd - entered.");

            if (__instance != null)
            {
                // Disable night vision
                if (ModState.IsNightVisionMode)
                {
                    VfxHelper.DisableNightVisionEffect();
                }
            }
        }
            public static void Postfix(CombatHUDActorInfo __instance, AbstractActor ___displayedActor)
            {
                Mod.Log.Trace?.Write("CHUDAI:RAI entered");

                if (___displayedActor == null || ModState.LastPlayerActorActivated == null)
                {
                    return;
                }

                if (__instance.StealthDisplay != null)
                {
                    VfxHelper.CalculateMimeticPips(__instance.StealthDisplay, ___displayedActor);
                }
            }
Пример #13
0
    private void Start()
    {
        // Assign enemy a colour
        if (characterColour == CharacterColour.None)
        {
            AssignEnemyColour(characterColour);
        }

        // Create a VFX where the enemy will spawn - just slightly above the stage (0.1f) - and change the VFX colour to match the enemy colour
        StartCoroutine(VfxHelper.CreateVFX(spawnVFX, transform.position + new Vector3(0, 0.01f, 0),
                                           Quaternion.identity, PlayerManager.colours.GetColour(characterColour), 0.5f));
        // "Spawn" the enemy (they float up through the stage)
        StartCoroutine(Spawn(gameObject, spawnSpeed, spawnDelay, spawnCooldown));
    }
Пример #14
0
    private void Start()
    {
        Color playerColour = PlayerManager.colours.GetColour(characterColour);

        // colour the player's weapon
        AssignWeaponColour(gameObject, playerColour);

        if (shouldSpawn)
        {
            // Create a VFX where the player will spawn - just slightly above the stage (0.1f) - and change the VFX colour to match the player colour
            StartCoroutine(VfxHelper.CreateVFX(spawnVFX, transform.position + new Vector3(0, 0.01f, 0), Quaternion.identity, playerColour, 0.5f));
            // "Spawn" the player (they float up through the stage)
            StartCoroutine(Spawn(gameObject, spawnSpeed, spawnDelay, spawnCooldown));
        }
    }
    private void Start()
    {
        playerInput = GetComponent <PlayerInput>();
        Color playerColour = PlayerManager.colours.GetColour(characterColour);

        // colour the player's weapon
        AssignWeaponColour(gameObject, playerColour);

        // Scale player damage based on number of levels cleared
        damage.AddModifier(LevelManager.Instance.GetNumLevelsCleared());

        if (shouldSpawn)
        {
            // Create a VFX where the player will spawn - just slightly above the stage (0.1f) - and change the VFX colour to match the player colour
            StartCoroutine(VfxHelper.CreateVFX(spawnVFX, transform.position + new Vector3(0, 0.01f, 0), Quaternion.identity, playerColour, 0.5f));
            // "Spawn" the player (they float up through the stage)
            StartCoroutine(Spawn(gameObject, spawnSpeed, spawnDelay, spawnCooldown));
        }
    }
Пример #16
0
        public static void Prefix(AbstractActor __instance, int stackItemID)
        {
            if (stackItemID == -1 || __instance == null || __instance.HasBegunActivation)
            {
                // For some bloody reason DoneWithActor() invokes OnActivationBegin, EVEN THOUGH IT DOES NOTHING. GAH!
                return;
            }

            // Draw stealth if applicable
            EWState actorState = new EWState(__instance);

            if (actorState.HasStealth())
            {
                Mod.Log.Debug?.Write($"-- Sending message to update stealth");
                StealthChangedMessage message = new StealthChangedMessage(__instance.GUID);
                __instance.Combat.MessageCenter.PublishMessage(message);
            }

            // If friendly, reset the map visibility
            if (__instance.TeamId != __instance.Combat.LocalPlayerTeamGuid &&
                __instance.Combat.HostilityMatrix.IsLocalPlayerFriendly(__instance.TeamId))
            {
                Mod.Log.Info?.Write($"{CombatantUtils.Label(__instance)} IS FRIENDLY, REBUILDING FOG OF WAR");

                if (actorState.HasNightVision() && ModState.GetMapConfig().isDark)
                {
                    Mod.Log.Info?.Write($"Enabling night vision mode.");
                    VfxHelper.EnableNightVisionEffect(__instance);
                }
                else
                {
                    // TODO: This is likely never triggered due to the patch below... remove?
                    if (ModState.IsNightVisionMode)
                    {
                        VfxHelper.DisableNightVisionEffect();
                    }
                }

                VfxHelper.RedrawFogOfWar(__instance);
            }
        }
    protected override void Update()
    {
        base.Update();

        // Handle attack charge ups
        if (_isPrimaryCharging)
        {
            _primaryChargeTime += Time.deltaTime;
            if (_primaryChargeTime >= primaryAttackChargeTime)
            {
                if (!_sparkleShown)
                {
                    StartCoroutine(VfxHelper.CreateVFX(sparkleVFX, transform.position + transform.forward * 1.6f + new Vector3(0, 2f, 0), transform.rotation));
                    StartCoroutine(AudioHelper.PlayAudioOverlap(WeaponAudio, sparkleSFX));
                    _sparkleShown = true;
                }
                // Clamp to max charge time
                _primaryChargeTime = primaryAttackChargeTime;
            }
        }
    }
Пример #18
0
    /// <summary>
    /// Sets the colour of the orb to the set colour when enabled
    /// </summary>
    private void OnEnable()
    {
        if (LaunchedByPlayer)
        {
            return;
        }

        // Select an orb colour randomly
        List <CharacterColour> orbColours = (LauncherStats as RhakStatsController).OrbsRequired;

        _colour = orbColours[Random.Range(0, orbColours.Count)];
        Color orbColour = PlayerManager.colours.GetColour(_colour);

        // Set the colour of the particle systems to the orb colour
        foreach (ParticleSystem p in colourParticleSystems)
        {
            VfxHelper.SetParticleSystemColour(p, orbColour);
        }

        // Set interactable colour
        _interactable.colour = _colour;
    }
Пример #19
0
    /// <summary>
    /// Enemy boss's tertiary attack
    /// </summary>
    public override void TertiaryAttack()
    {
        if (AttackCooldown > 0f)
        {
            return;
        }

        Anim.SetTrigger("TertiaryAttack");
        // audio
        StartCoroutine(AudioHelper.PlayAudioOverlap(WeaponAudio, tertiaryAttackSFX));

        StartCoroutine(VfxHelper.CreateVFX(tertiaryAttackVFX, gameObject.transform.position + new Vector3(0, 1f, 0), gameObject.transform.rotation,
                                           PlayerManager.colours.GetColour(Stats.characterColour), tertiaryAttackDelay * 0.5f));

        // Attack any enemies within the attack sweep and range
        foreach (GameObject player in Players.Where(player => CanDamageTarget(player.transform.position, attackRadius, attackAngle)))
        {
            // Calculate and perform damage
            StartCoroutine(PerformDamage(player.GetComponent <EntityStatsController>(), Stats.ComputeDamageModifer(), tertiaryAttackDelay * 0.5f));
        }
        AttackCooldown = tertiaryAttackCooldown;
    }
Пример #20
0
 private void UpdateRespawnPercentage(bool playersOnBeacon)
 {
     if (playersOnBeacon)
     {
         respawnPercentage += respawnRate;
         if (respawnPercentage >= 100f)
         {
             playerStatsController.Respawn();
             StartCoroutine(VfxHelper.CreateVFX(respawnEffectPrefab, transform.position + new Vector3(0, 0.01f, 0), Quaternion.identity, PlayerManager.colours.GetColour(playerStatsController.characterColour)));
             Destroy(gameObject);
         }
     }
     else
     {
         respawnPercentage = Mathf.Max(0, respawnPercentage - 2f * respawnRate);
         if (respawnPercentage <= 0)
         {
             text.text = reviveText;
             return;
         }
     }
     text.text = respawnPercentage.ToString("N0") + "%";
 }
        public static void Postfix(PilotableActorRepresentation __instance, VisibilityLevel newLevel)
        {
            Mod.Log.Trace?.Write("PAR:OPVC entered.");

            Traverse      parentT     = Traverse.Create(__instance).Property("parentActor");
            AbstractActor parentActor = parentT.GetValue <AbstractActor>();

            if (parentActor == null)
            {
                Mod.Log.Trace?.Write($"ParentActor is null, skipping!");
                return;
            }

            EWState parentState = new EWState(parentActor);

            if (newLevel == VisibilityLevel.LOSFull)
            {
                if (parentState.HasStealth())
                {
                    VfxHelper.EnableStealthVfx(parentActor);
                }
                else
                {
                    VfxHelper.DisableSensorStealthEffect(parentActor);
                }

                if (parentState.HasMimetic())
                {
                    VfxHelper.EnableMimeticEffect(parentActor);
                }
                else
                {
                    VfxHelper.DisableMimeticEffect(parentActor);
                }

                __instance.BlipObjectUnknown.SetActive(false);
                __instance.BlipObjectUnknown.SetActive(false);
            }
            else if (newLevel >= VisibilityLevel.Blip0Minimum)
            {
                Mod.Log.Debug?.Write($"Actor: {CombatantUtils.Label(parentActor)} has changed player visibility to: {newLevel}");

                if (parentActor.team.IsFriendly(parentActor.Combat.LocalPlayerTeam))
                {
                    Mod.Log.Debug?.Write($" Target actor is friendly, forcing blip off");
                    __instance.BlipObjectUnknown.SetActive(false);
                }
                else
                {
                    // Because Blip1 corresponds to ArmorAndWeapon, go ahead and show the model as the chassis is 'known'
                    if (newLevel >= VisibilityLevel.Blip1Type)
                    {
                        Mod.Log.Debug?.Write($" Actor is a foe,  disabling the identified blip and showing the object");
                        __instance.VisibleObject.SetActive(true);
                        __instance.BlipObjectIdentified.SetActive(false);

                        __instance.BlipObjectUnknown.transform.localScale = new Vector3(1f, 0.8f, 1f);
                        __instance.BlipObjectUnknown.SetActive(true);
                    }
                }
            }
        }