예제 #1
0
        private void PaintSelectedItem()
        {
            var itemModel = SelectedItem.ItemModel;

            SelectedItemText.text = itemModel.Name;
            var itemDef = InventoryModel.GetDef(itemModel.Name);

            if (itemDef == null)
            {
                SelectedItemDescription.text = "{missing def}";
            }
            else
            {
                SelectedItemText.text        = itemDef.NiceName;
                SelectedItemDescription.text = itemDef.Description;
                Texture2D tex = CoreUtils.LoadResource <Texture2D>("UI/Icons/" + itemDef.Image);
                if (tex != null)
                {
                    SelectedItemImage.texture = tex;
                }
            }

            SelectedItemStats.text = itemModel.GetStatsString();


            TransferButton.gameObject.SetActive(true);
            var transferButtonText = TransferButton.GetComponentInChildren <Text>();

            if (Selected == SelectedState.Container && !IsShop)
            {
                transferButtonText.text = "< Transfer";
            }
            else if (Selected == SelectedState.Inventory && !IsShop)
            {
                transferButtonText.text = "Transfer >";
            }
            else if (Selected == SelectedState.Container && IsShop)
            {
                transferButtonText.text = "< Buy";
            }
            else if (Selected == SelectedState.Inventory && IsShop)
            {
                transferButtonText.text = "Sell >";
            }

            if (IsShop && Selected == SelectedState.Container)
            {
                int adjValue = RpgValues.AdjustedBuyPrice(GameState.Instance.PlayerRpgState, itemModel.Value);
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", adjValue, adjValue * 1, itemModel.Weight, itemModel.Weight * 1);
            }
            else if (IsShop && Selected == SelectedState.Inventory)
            {
                int adjValue = RpgValues.AdjustedSellPrice(GameState.Instance.PlayerRpgState, itemModel.Value);
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", adjValue, adjValue * 1, itemModel.Weight, itemModel.Weight * 1);
            }
            else
            {
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", itemModel.Value, itemModel.Value * 1, itemModel.Weight, itemModel.Weight * 1);
            }
        }
예제 #2
0
        public void TakeDamage(ActorHitInfo data)
        {
            if (MetaState.Instance.SessionFlags.Contains("GodMode") || GameState.Instance.PlayerFlags.Contains(PlayerFlags.Invulnerable) || IsDying)
            {
                return;
            }

            CharacterModel playerModel = GameState.Instance.PlayerRpgState;

            //damage model is very stupid right now, we will make it better later
            var(dt, dr) = playerModel.GetDamageThresholdAndResistance(data.DamageType);
            float damageTaken = RpgValues.DamageTaken(data.Damage, data.DamagePierce, dt, dr);

            if (data.HitLocation == (int)ActorBodyPart.Head)
            {
                damageTaken *= 2.0f;
            }
            else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg)
            {
                damageTaken *= 0.75f;
            }

            if (damageTaken > 0)
            {
                if (PainSound != null && !PainSound.isPlaying)
                {
                    PainSound.Play();
                }
            }

            playerModel.Health -= damageTaken;
        }
예제 #3
0
 void OnEnable()
 {
     if (CheckLevelUp && GameState.Instance.PlayerRpgState.Experience >= RpgValues.XPToNext(GameState.Instance.PlayerRpgState.Level))
     {
         DefaultLevelUpModal.PushModal(OnLevelUpDone);
     }
 }
예제 #4
0
        public void OnQuantityValueChanged()
        {
            if (SelectedItem == null)
            {
                return;
            }

            var itemModel    = SelectedItem.ItemModel;
            int itemQuantity = Convert.ToInt32(QuantityInputField.text);

            //clamp values
            if (itemQuantity <= 0 || itemQuantity > SelectedItem.Quantity)
            {
                itemQuantity            = MathUtils.Clamp <int>(itemQuantity, 1, SelectedItem.Quantity);
                QuantityInputField.text = itemQuantity.ToString();
            }

            if (IsShop && Selected == SelectedState.Container)
            {
                int adjValue = RpgValues.AdjustedBuyPrice(GameState.Instance.PlayerRpgState, itemModel.Value);
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", adjValue, adjValue * itemQuantity, itemModel.Weight, itemModel.Weight * itemQuantity);
            }
            else if (IsShop && Selected == SelectedState.Inventory)
            {
                int adjValue = RpgValues.AdjustedSellPrice(GameState.Instance.PlayerRpgState, itemModel.Value);
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", adjValue, adjValue * itemQuantity, itemModel.Weight, itemModel.Weight * itemQuantity);
            }
            else
            {
                TransferText.text = string.Format("Value: {0}({1}) | Weight: {2}({3})", itemModel.Value, itemModel.Value * itemQuantity, itemModel.Weight, itemModel.Weight * itemQuantity);
            }
        }
예제 #5
0
        private void CalculateValues()
        {
            var player = GameState.Instance.PlayerRpgState;
            int levels = RpgValues.LevelsForExperience(player);

            for (int i = 0, tLevel = player.Level; i < levels; i++, tLevel++)
            {
                PotentialPoints += RpgValues.PotentialPointsForLevel(tLevel, player);
            }

            NewLevel = player.Level + levels;

            //copy stats set
            NewStats = new StatsSet(player.BaseStats);
        }
예제 #6
0
 public void OnClickContinue()
 {
     if (PotentialPoints == 0)
     {
         GameState.Instance.PlayerRpgState.Experience       = RpgValues.XPAfterMaxLevel(GameState.Instance.PlayerRpgState);
         GameState.Instance.PlayerRpgState.Level            = NewLevel;
         GameState.Instance.PlayerRpgState.BaseStats.Skills = NewStats.Skills; //assign points
         GameState.Instance.PlayerRpgState.UpdateStats();
         Destroy(this.gameObject);
         Callback.Invoke();
     }
     else
     {
         //display a error
         Modal.PushMessageModal("You must assign all Potential Points", "Information", null, null);
     }
 }
예제 #7
0
        protected void HandleMovement()
        {
            var playerModel = GameState.Instance.PlayerRpgState;

            if (!GameState.Instance.PlayerFlags.Contains(PlayerFlags.Frozen) && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.TotallyFrozen))
            {
                //handle running
                float energyToRun = RpgValues.GetRunEnergyRate(playerModel);

                IsRunning = MappedInput.GetButton(DefaultControls.Sprint);

                if (RunWasBlocked && IsRunning)
                {
                    IsRunning = false;
                }
                else if (RunWasBlocked && !IsRunning)
                {
                    RunWasBlocked = false;
                }

                if (IsRunning && playerModel.Energy < energyToRun)
                {
                    IsRunning     = false;
                    RunWasBlocked = true;
                    QdmsMessageBus.Instance.PushBroadcast(new QdmsFlagMessage("RpgInsufficientEnergy"));
                }


                //TODO check against energy requirements

                //request an exit from ADS
                if (IsRunning && PlayerController.WeaponComponent != null)
                {
                    PlayerController.WeaponComponent.RequestADSExit();
                }

                //handle crouching
                if (MappedInput.GetButtonDown(DefaultControls.Crouch) && !IsRunning)
                {
                    IsCrouching     = !IsCrouching;
                    DidChangeCrouch = true;
                    SetCrouchState();
                }

                //uncrouch if we try to sprint
                if (IsRunning && IsCrouching)
                {
                    IsCrouching     = false;
                    DidChangeCrouch = true;
                    SetCrouchState();
                }

                if (IsGrounded)
                {
                    //normal x/y movement

                    var flatVelocity = new Vector3(Velocity.x, 0, Velocity.z);

                    Vector3 moveVector = Vector3.zero;

                    float maxAcceleration = IsCrouching ? MaxCrouchAcceleration : (IsRunning ? MaxSprintAcceleration : MaxWalkAcceleration);
                    if (Mathf.Abs(MappedInput.GetAxis(DefaultControls.MoveY)) > InputDeadzone)
                    {
                        moveVector += (transform.forward * MappedInput.GetAxis(DefaultControls.MoveY) * maxAcceleration * Time.deltaTime);
                        IsMoving    = true;
                    }

                    if (Mathf.Abs(MappedInput.GetAxis(DefaultControls.MoveX)) > InputDeadzone)
                    {
                        moveVector += (transform.right * MappedInput.GetAxis(DefaultControls.MoveX) * maxAcceleration * Time.deltaTime);
                        IsMoving    = true;
                    }

                    if (Mathf.Approximately(moveVector.magnitude, 0) && !IsOnSlope)
                    {
                        moveVector = -flatVelocity.normalized * Mathf.Min(MaxBrakeAcceleration * Time.deltaTime, flatVelocity.magnitude);
                    }

                    //clamp velocity to maxwalk/maxrun/etc
                    float maxSpeed = IsCrouching ? MaxCrouchSpeed * RpgValues.GetMoveSpeedMultiplier(playerModel) : (IsRunning ? MaxSprintSpeed * RpgValues.GetRunSpeedMultiplier(playerModel) : MaxWalkSpeed * RpgValues.GetMoveSpeedMultiplier(playerModel));
                    maxSpeed *= ConfigState.Instance.GetGameplayConfig().Difficulty.PlayerAgility;
                    var newFlatVelocity = new Vector3(Velocity.x, 0, Velocity.z) + new Vector3(moveVector.x, 0, moveVector.z);
                    if (newFlatVelocity.magnitude > maxSpeed)
                    {
                        newFlatVelocity = newFlatVelocity.normalized * maxSpeed; //this actually doesn't make a ton of physical sense but it does seem to work
                    }

                    Velocity = new Vector3(newFlatVelocity.x, Velocity.y, newFlatVelocity.z);

                    if (IsRunning)
                    {
                        playerModel.Energy -= energyToRun;
                    }
                }
                else
                {
                    //air move: component wise, clamped

                    //awkward bullshit to go from world to player space
                    Vector3 refVelocity    = Quaternion.AngleAxis(-transform.eulerAngles.y, Vector3.up) * Velocity;
                    Vector3 newAddVelocity = Vector3.zero;

                    float multiplier = ConfigState.Instance.GetGameplayConfig().Difficulty.PlayerAgility;
                    multiplier *= RpgValues.GetAirMoveMultiplier(playerModel);

                    float maxSpeedScaled = MaxAirSpeed * multiplier;

                    float moveZ = MappedInput.GetAxis(DefaultControls.MoveY) * MaxAirAcceleration * multiplier * Time.deltaTime;
                    if (Mathf.Abs(refVelocity.z) < maxSpeedScaled || Mathf.Sign(moveZ) != Mathf.Sign(refVelocity.z))
                    {
                        newAddVelocity += new Vector3(0, 0, moveZ);
                    }

                    float moveX = MappedInput.GetAxis(DefaultControls.MoveX) * MaxAirAcceleration * multiplier * Time.deltaTime;
                    if (Mathf.Abs(refVelocity.x) < maxSpeedScaled || Mathf.Sign(moveX) != Mathf.Sign(refVelocity.x))
                    {
                        newAddVelocity += new Vector3(moveX, 0, 0);
                    }

                    Velocity += Quaternion.AngleAxis(transform.eulerAngles.y, Vector3.up) * newAddVelocity;
                }

                if (IsGrounded && (AllowSlopeJumping || !IsOnSlope))
                {
                    //jumping
                    if (MappedInput.GetButtonDown(DefaultControls.Jump))
                    {
                        var   jumpVelocity  = JumpInstantaneousVelocity * RpgValues.GetJumpVelocityMultiplier(playerModel) * ConfigState.Instance.GetGameplayConfig().Difficulty.PlayerAgility;
                        float jumpEnergyUse = RpgValues.GetJumpEnergyUse(playerModel);

                        if (playerModel.Energy >= jumpEnergyUse)
                        {
                            playerModel.Energy -= jumpEnergyUse;
                            bool wasCrouched = IsCrouching;

                            //uncrouch if we were crouched
                            if (wasCrouched)
                            {
                                IsCrouching     = false;
                                DidChangeCrouch = true;
                                SetCrouchState();
                                jumpVelocity += JumpCrouchBoostVelocity;
                            }

                            Velocity += Quaternion.AngleAxis(transform.eulerAngles.y, Vector3.up) * jumpVelocity;
                            CharController.Move(Quaternion.AngleAxis(transform.eulerAngles.y, Vector3.up) * JumpInstantaneousDisplacement);
                            JumpSound.Ref()?.Play();
                            DidJump = true;
                        }
                        else
                        {
                            //failed to jump
                            QdmsMessageBus.Instance.PushBroadcast(new QdmsFlagMessage("RpgInsufficientEnergy"));
                        }
                    }
                }
            }

            //energy recovery
            if (!IsRunning && IsGrounded && !DidJump)
            {
                float energyGain = (IsMoving ? RpgValues.GetMovingEnergyRecoveryRate(playerModel) : RpgValues.GetIdleEnergyRecoveryRate(playerModel)) * Time.deltaTime;
                playerModel.Energy = Mathf.Min(playerModel.DerivedStats.MaxEnergy, playerModel.Energy + energyGain);
            }
        }
예제 #8
0
        protected void HandleDynamicMovement()
        {
            if (GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoPhysics)) //probably buggy
            {
                return;
            }

            float lastYVelocity = Velocity.y; //last y-velocity, ignoring gravity

            Velocity += Physics.gravity * GravityMultiplier * Time.deltaTime;

            CharController.Move(Velocity * Time.deltaTime);

            IsGrounded = CharController.isGrounded;
            IsOnSlope  = Vector3.Angle(Vector3.up, LastGroundNormal) > CharController.slopeLimit;

            if (IsGrounded && !DidJump)
            {
                //float yDamp = GroundedDamping * Time.deltaTime;
                //yDamp = Mathf.Min(yDamp, Mathf.Abs(Velocity.y));
                //yDamp = yDamp * -Mathf.Sign(Velocity.y);
                //Velocity += new Vector3(0, yDamp, 0);

                if (lastYVelocity < -FallMinDetectVelocity && TimeInAir > FallMinDetectTime)
                {
                    FallImpactSound.Ref()?.Play();

                    if (lastYVelocity < -FallMinGruntVelocity)
                    {
                        FallPainSound.Ref()?.Play();
                    }

                    if (GameParams.UseFallDamage && !MetaState.Instance.SessionFlags.Contains("GodMode") && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoFallDamage) && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.Invulnerable))
                    {
                        GameState.Instance.PlayerRpgState.Health -= RpgValues.FallDamage(GameState.Instance.PlayerRpgState, new Vector3(Velocity.x, lastYVelocity, Velocity.z));
                    }

                    //Debug.Log($"Player fell (y-velocity = {lastYVelocity:F4} m/s, time in air = {TimeInAir:F2} s)");
                }

                Velocity  = new Vector3(Velocity.x, 0, Velocity.z);
                TimeInAir = 0;
            }

            if (IsGrounded && IsOnSlope)
            {
                //Debug.Log("on slope");
                //slope slide
                Vector3 slopeDir         = new Vector3(LastGroundNormal.x, 1f - LastGroundNormal.y, LastGroundNormal.z).normalized;
                Vector3 slopeVelocityAdd = new Vector3(slopeDir.x, 0, slopeDir.z) * SlopeSlideAccleration * Time.deltaTime;
                Vector3 flatVelocity     = new Vector3(Velocity.x, 0, Velocity.z);
                slopeVelocityAdd = slopeVelocityAdd.normalized * Mathf.Min(slopeVelocityAdd.magnitude, Mathf.Max(0, SlopeSlideSpeed - flatVelocity.magnitude));
                Velocity        += slopeVelocityAdd;
            }
            else if (IsGrounded && !IsMoving)
            {
                //ground friction
                Velocity += new Vector3(-Velocity.x, 0, -Velocity.z).normalized *GroundFriction *Time.deltaTime;
            }
            else
            {
                //air resistance
                Velocity  += (-Velocity).normalized * Mathf.Min(AirResistance * Time.deltaTime, Velocity.magnitude);
                TimeInAir += Time.deltaTime;
            }
        }
예제 #9
0
        public void TakeDamage(ActorHitInfo data)
        {
            if (!data.HarmFriendly)
            {
                string hitFaction = data.OriginatorFaction;
                if (!string.IsNullOrEmpty(hitFaction))
                {
                    FactionRelationStatus relation = FactionModel.GetRelation(hitFaction, Faction); //this looks backwards but it's because we're checking if the Bullet is-friendly-to the Actor
                    if (relation == FactionRelationStatus.Friendly)
                    {
                        return; //no friendly fire
                    }
                }
            }

            //damage model is very stupid right now, we will make it better later
            float dt          = data.DamageType < DamageThreshold.Length ? DamageThreshold[(int)data.DamageType] : 0f;
            float dr          = data.DamageType < DamageThreshold.Length ? DamageResistance[(int)data.DamageType] : 0f;
            float damageTaken = RpgValues.DamageTaken(data.Damage, data.DamagePierce, dt, dr);

            if (data.HitLocation == (int)ActorBodyPart.Head)
            {
                damageTaken *= 2.0f;
            }
            else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg)
            {
                damageTaken *= 0.75f;
            }

            damageTaken *= (1f / ConfigState.Instance.GetGameplayConfig().Difficulty.ActorStrength);

            if (!Invincible)
            {
                Health -= damageTaken;
            }

            if (CurrentAiState == ActorAiState.Dead) //abort if we're already dead
            {
                return;
            }

            bool didTakePain = UnityEngine.Random.Range(0f, 1f) < PainChance; //shouldn't this be weighted by damage?

            if (Defensive && data.Originator != null && data.Originator != this)
            {
                FactionRelationStatus relation = FactionRelationStatus.Neutral;
                if (data.Originator is PlayerController)
                {
                    relation = FactionModel.GetRelation(Faction, "Player");
                }
                else if (data.Originator is ActorController)
                {
                    relation = FactionModel.GetRelation(Faction, ((ActorController)data.Originator).Faction);
                }

                if (relation != FactionRelationStatus.Friendly || Infighting)
                {
                    Target  = data.Originator.transform;
                    BeenHit = true;

                    if (DisableInteractionOnHit && InteractionComponent != null)
                    {
                        InteractionComponent.InteractionDisabledByHit = true;
                    }

                    if (FeelPain && didTakePain)
                    {
                        if (CurrentAiState != ActorAiState.Hurting)
                        {
                            EnterState(ActorAiState.Hurting);
                        }
                        else
                        {
                            EnterState(ActorAiState.Chasing);
                        }
                    }
                }
                else if (CurrentAiState != ActorAiState.Hurting)
                {
                    EnterState(ActorAiState.Hurting);
                }
            }
            else if (FeelPain && didTakePain && CurrentAiState != ActorAiState.Hurting)
            {
                EnterState(ActorAiState.Hurting);
            }
        }
예제 #10
0
        public override void SignalPaint()
        {
            CharacterModel pModel = GameState.Instance.PlayerRpgState;

            //PlayerControl pControl = PlayerControl.Instance;

            //repaint
            HealthText.text = string.Format("Health: {0}/{1}", (int)pModel.Health, (int)pModel.DerivedStats.MaxHealth);
            ArmorText.text  = string.Format("Level: {0} ({1}/{2} XP)\n", pModel.Level, pModel.Experience, RpgValues.XPToNext(pModel.Level));

            string equipText = string.Format("Armor: {0}\nLH Weapon: {1}\nRH Weapon: {2}",
                                             GetNameForSlot(EquipSlot.Body, pModel), GetNameForSlot(EquipSlot.LeftWeapon, pModel), GetNameForSlot(EquipSlot.RightWeapon, pModel));

            AmmoText.text = equipText;

            LevelUpButton.interactable = !GameState.Instance.MenuGameStateLocked;

            //this is now somewhat broken because there are more choices in the struct
            string rid = pModel.Gender == Sex.Female ? "portrait_f" : "portrait_m";

            CharacterImage.texture = CoreUtils.LoadResource <Texture2D>("UI/Portraits/" + rid);
        }
예제 #11
0
        public void TakeDamage(ActorHitInfo data)
        {
            //damage model is very stupid right now, we will make it better later
            float dt          = data.DamageType < DamageThreshold.Length ? DamageThreshold[(int)data.DamageType] : 0f;
            float dr          = data.DamageType < DamageThreshold.Length ? DamageResistance[(int)data.DamageType] : 0f;
            float damageTaken = RpgValues.DamageTaken(data.Damage, data.DamagePierce, dt, dr);

            if (data.HitLocation == (int)ActorBodyPart.Head)
            {
                damageTaken *= 2.0f;
            }
            else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg)
            {
                damageTaken *= 0.75f;
            }

            damageTaken *= (1f / ConfigState.Instance.GetGameplayConfig().Difficulty.ActorStrength);

            if (!Invincible)
            {
                Health -= damageTaken;
            }

            /*
             * if(!string.IsNullOrEmpty(data.HitPuff))
             * {
             *  Debug.Log($"Spawning hitpuff \"{data.HitPuff}\" at {data.HitCoords}");
             *  Vector3 hitCoords = data.HitCoords.HasValue ? data.HitCoords.Value : transform.position;
             *  WorldUtils.SpawnEffect(data.HitPuff, hitCoords, transform.eulerAngles, null);
             * }
             * else if(!string.IsNullOrEmpty(DefaultHitPuff))
             * {
             *  Vector3 hitCoords = data.HitCoords.HasValue ? data.HitCoords.Value : transform.position;
             *  WorldUtils.SpawnEffect(DefaultHitPuff, hitCoords, transform.eulerAngles, null);
             * }
             */
            //we no longer spawn hitpuffs here

            if (CurrentAiState == ActorAiState.Dead) //abort if we're already dead
            {
                return;
            }

            bool didTakePain = UnityEngine.Random.Range(0f, 1f) < PainChance;

            if (Defensive && data.Originator != null && data.Originator != this)
            {
                FactionRelationStatus relation = FactionRelationStatus.Neutral;
                if (data.Originator is PlayerController)
                {
                    relation = FactionModel.GetRelation(Faction, "Player");
                }
                else if (data.Originator is ActorController)
                {
                    relation = FactionModel.GetRelation(Faction, ((ActorController)data.Originator).Faction);
                }

                if (relation != FactionRelationStatus.Friendly || Infighting)
                {
                    Target  = data.Originator.transform;
                    BeenHit = true;

                    if (DisableInteractionOnHit && InteractionComponent != null)
                    {
                        InteractionComponent.InteractionDisabledByHit = true;
                    }

                    if (FeelPain && didTakePain)
                    {
                        EnterState(ActorAiState.Hurting);
                    }
                    else
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                else
                {
                    EnterState(ActorAiState.Hurting);
                }
            }
            else if (FeelPain && didTakePain)
            {
                EnterState(ActorAiState.Hurting);
            }
        }
예제 #12
0
        private void SelectTarget()
        {
            var gameplayConfig = ConfigState.Instance.GetGameplayConfig();

            if (TotalTickCount % SearchInterval * (1f / gameplayConfig.Difficulty.ActorAggression) != 0)
            {
                return;
            }

            var detectionDifficultyFactor = 1f / gameplayConfig.Difficulty.ActorPerception;

            //check player first since it's (relatively) cheap
            if (FactionModel.GetRelation(Faction, "Player") == FactionRelationStatus.Hostile && !MetaState.Instance.SessionFlags.Contains("NoTarget") && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget))
            {
                var playerObj = WorldUtils.GetPlayerObject();
                if (playerObj != null && RpgWorldUtils.TargetIsAlive(playerObj.transform))
                {
                    PlayerController pc = playerObj.GetComponent <PlayerController>();

                    if ((playerObj.transform.position - transform.position).magnitude <= SearchRadius &&
                        UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) <= RpgValues.DetectionChance(GameState.Instance.PlayerRpgState, pc.MovementComponent.IsCrouching, pc.MovementComponent.IsRunning))
                    {
                        if (UseLineOfSight)
                        {
                            //additional check
                            RaycastHit hitinfo;
                            if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (playerObj.transform.position - transform.position), out hitinfo))
                            {
                                if (hitinfo.collider.gameObject == playerObj)
                                {
                                    Target = playerObj.transform;
                                    return;
                                }
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = playerObj.transform;
                            return;
                        }
                    }
                }
            }

            //if(TargetNpc)
            {
                //var sw = System.Diagnostics.Stopwatch.StartNew();

                //new code should be faster if n is large but it may not bear out in practice, and it probably allocs more dedotated wam

                var colliders = Physics.OverlapSphere(transform.position, SearchRadius, LayerMask.GetMask("Default", "ActorHitbox"));
                HashSet <ActorController> potentialTargets = new HashSet <ActorController>();

                foreach (var collider in colliders)
                {
                    var actorController = collider.GetComponent <ActorController>();
                    if (actorController != null)
                    {
                        potentialTargets.Add(actorController);
                        break;
                    }

                    var hitboxComponent = collider.GetComponent <IHitboxComponent>();
                    if (hitboxComponent != null && hitboxComponent.ParentController is ActorController hitboxAC)
                    {
                        potentialTargets.Add(hitboxAC);
                        break;
                    }
                }


                //old stupid code: should work well enough as long as n is small and your computer is fast enough
                //IEnumerable<ActorController> potentialTargets = transform.root.GetComponentsInChildren<ActorController>();

                foreach (var potentialTarget in potentialTargets)
                {
                    if (RpgWorldUtils.TargetIsAlive(potentialTarget.transform) &&
                        (potentialTarget.transform.position - transform.position).magnitude <= SearchRadius &&
                        FactionModel.GetRelation(Faction, potentialTarget.Faction) == FactionRelationStatus.Hostile &&
                        !(potentialTarget == this))
                    {
                        //roll some dice
                        if (potentialTarget.Detectability < 1 && UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) > potentialTarget.Detectability) //probably correct
                        {
                            continue;
                        }

                        if (UseLineOfSight)
                        {
                            //additional check
                            RaycastHit hitinfo;
                            if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (potentialTarget.transform.position - transform.position), out hitinfo))
                            {
                                if (hitinfo.collider.gameObject == potentialTarget.gameObject)
                                {
                                    Target = potentialTarget.transform;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            //otherwise, close enough
                            Target = potentialTarget.transform;
                            break;
                        }
                    }
                }

                //sw.Stop();
                //Debug.Log($"Target lookup: {sw.Elapsed.TotalMilliseconds:F4} ms");
            }

            if (!RpgWorldUtils.TargetIsAlive(Target))
            {
                Target = null;
            }
        }
예제 #13
0
        //on actual level handler
        public void OnClickLevelUp()
        {
            NewStats.Skills[(SkillType)SelectedSkill] = NewStats.Skills[(SkillType)SelectedSkill] + RpgValues.SkillGainForPoints(1);
            PotentialPoints--;

            UpdateValues();
        }
예제 #14
0
        public void OnSkillSelected(int i, Button b)
        {
            //Debug.Log(Enum.GetName(typeof(SkillType), i));

            //set selected index, paint detail, enable buttons if valid
            var skillName = Enum.GetName(typeof(SkillType), i);

            SelectedSkill = i;
            DetailPanel.SetActive(true);
            DetailTitle.text           = Sub.Replace(skillName, SubList);
            DetailDescription.text     = Sub.Exists(skillName, DescriptionList) ? Sub.Replace(skillName, DescriptionList) : string.Empty;
            DetailLevel.text           = string.Format("{0}->{1}", NewStats.Skills[(SkillType)i], NewStats.Skills[(SkillType)i] + RpgValues.SkillGainForPoints(1));
            LevelUpButton.interactable = (PotentialPoints > 0);
        }
예제 #15
0
        private void UpdateValues()
        {
            //update buttons
            for (int i = 0; i < SkillButtons.Length; i++)
            {
                string name = Enum.GetName(typeof(SkillType), i);

                Button b = SkillButtons[i];
                b.GetComponentInChildren <Text>().text = string.Format("{0} [{1}]", Sub.Replace(name, SubList), NewStats.Skills[(SkillType)i]);
            }

            //update details
            DetailLevel.text = string.Format("{0}->{1}", NewStats.Skills[(SkillType)SelectedSkill], NewStats.Skills[(SkillType)SelectedSkill] + RpgValues.SkillGainForPoints(1));

            //if we're out of PP, set buttons
            LevelUpButton.interactable = (PotentialPoints > 0);
            ConfirmButton.interactable = (PotentialPoints == 0);

            PointsText.text = string.Format("Potential Points: {0}", PotentialPoints);
        }
예제 #16
0
        public void OnClickTransfer()
        {
            //immediate fail conditions
            if (Selected == SelectedState.None || SelectedItem == null)
            {
                return;
            }

            int quantity = MathUtils.Clamp <int>(Convert.ToInt32(QuantityInputField.text), 1, Mathf.Abs(SelectedItem.Quantity));

            //if it's a shop and we don't have money, check and possibly fail
            //(we would also handle carry weight here if that was actually implemented ?)
            if (IsShop)
            {
                string moneyTypeName = Enum.GetNames(typeof(MoneyType))[0];

                if (Selected == SelectedState.Inventory)
                {
                    //we are SELLING, check CONTAINER money
                    int neededMoney = Mathf.RoundToInt(quantity * RpgValues.AdjustedSellPrice(GameState.Instance.PlayerRpgState, SelectedItem.ItemModel.Value));
                    int haveMoney   = Container.CountItem(moneyTypeName);

                    if (neededMoney > haveMoney)
                    {
                        Modal.PushMessageModal(string.Format("This shop doesn't have enough currency to pay for that (have {0}, need {1})", haveMoney, neededMoney), "Insufficient Currency", null, null);
                        return;
                    }
                    else
                    {
                        //var iMoneyItem = Inventory.FindItem(moneyTypeName)[0]; //it's weirdly asymmetrical and I don't know why
                        Inventory.AddItem(moneyTypeName, neededMoney);

                        var cMoneyItem = Container.FindItem(moneyTypeName)[0];
                        Container.TakeItem(cMoneyItem, neededMoney);
                    }
                }
                else if (Selected == SelectedState.Container)
                {
                    //we are BUYING, check PLAYER money
                    int neededMoney = Mathf.RoundToInt(quantity * RpgValues.AdjustedBuyPrice(GameState.Instance.PlayerRpgState, SelectedItem.ItemModel.Value));
                    int haveMoney   = Inventory.CountItem(moneyTypeName);

                    if (neededMoney > haveMoney)
                    {
                        Modal.PushMessageModal(string.Format("You don't have enough currency to pay for that (have {0}, need {1})", haveMoney, neededMoney), "Insufficient Currency", null, null);
                        return;
                    }
                    else
                    {
                        var iMoneyItem = Inventory.FindItem(moneyTypeName)[0];
                        Inventory.RemoveItem(iMoneyItem, neededMoney);

                        var cMoneyItem = Container.FindItem(moneyTypeName)[0];
                        Container.PutItem(cMoneyItem, neededMoney);
                    }
                }
            }

            //simpler cases: transferring inventory to container or vice versa
            if (Selected == SelectedState.Inventory)
            {
                //transfer item to container
                if (!SelectedItem.ItemModel.Stackable)
                {
                    Inventory.RemoveItem(SelectedItem);
                    Container.PutItem(SelectedItem);
                }
                else
                {
                    Inventory.RemoveItem(SelectedItem, quantity);
                    Container.PutItem(SelectedItem, quantity);
                }
            }
            else if (Selected == SelectedState.Container)
            {
                //transfer item to inventory
                if (!SelectedItem.ItemModel.Stackable)
                {
                    Inventory.AddItem(SelectedItem);
                    Container.TakeItem(SelectedItem);
                }
                else
                {
                    Inventory.AddItem(SelectedItem.ItemModel.Name, quantity);
                    Container.TakeItem(SelectedItem, quantity);
                }
            }

            //don't forget to fix the stacks!
            Container.FixStacks();

            //clear and repaint
            ClearState();
            PaintAll();
        }
예제 #17
0
        public void TakeDamage(ActorHitInfo data)
        {
            if (MetaState.Instance.SessionFlags.Contains("GodMode") || GameState.Instance.PlayerFlags.Contains(PlayerFlags.Invulnerable) || IsDying)
            {
                return;
            }

            if (!data.HarmFriendly)
            {
                string hitFaction = data.OriginatorFaction;
                if (!string.IsNullOrEmpty(hitFaction))
                {
                    FactionRelationStatus relation = FactionModel.GetRelation(hitFaction, PredefinedFaction.Player.ToString()); //this looks backwards but it's because we're checking if the Bullet is-friendly-to the Actor
                    if (relation == FactionRelationStatus.Friendly)
                    {
                        return; //no friendly fire
                    }
                }
            }

            if (DamageHandler != null)
            {
                var hitOut = DamageHandler(data);
                if (hitOut.HasValue)
                {
                    data = hitOut.Value;
                }
                else
                {
                    return;
                }
            }

            CharacterModel playerModel = GameState.Instance.PlayerRpgState;

            var(damageToShields, damageToArmor, damageToCharacter) = RpgValues.DamageRatio(data.Damage, data.DamagePierce, playerModel);

            float oldShields = playerModel.Shields;

            playerModel.Shields -= damageToShields;

            if (oldShields > 0 && playerModel.Shields <= 0)
            {
                MessageInterface.PushToBus(new QdmsFlagMessage("PlayerShieldsLost"));
                ShieldComponent.Ref()?.SignalLostShields();
            }

            var(dt, dr) = playerModel.GetDamageThresholdAndResistance(data.DamageType);
            float damageTaken = RpgValues.DamageTaken(damageToArmor, damageToCharacter, dt, dr);

            if (data.HitLocation == (int)ActorBodyPart.Head)
            {
                damageTaken *= 2.0f;
            }
            else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg)
            {
                damageTaken *= 0.75f;
            }

            playerModel.Health -= damageTaken;

            if (damageTaken > PainSoundThreshold)
            {
                if (PainSound != null && !PainSound.isPlaying)
                {
                    PainSound.Play();
                }
            }

            if (damageToShields > 0 || damageTaken > 0)
            {
                ShieldComponent.Ref()?.SignalTookDamage(damageToShields, damageTaken);

                var damageValues = new Dictionary <string, object>()
                {
                    { "DamageTaken", damageTaken },
                    { "DamageToShields", damageToShields },
                    { "DamageToArmor", damageToArmor },
                    { "DamageToCharacter", damageToCharacter }
                };
                MessageInterface.PushToBus(new QdmsKeyValueMessage(damageValues, "PlayerTookDamage"));
            }
        }
예제 #18
0
        private void PaintStats()
        {
            StringBuilder statsSB = new StringBuilder(); //really can't guess here

            var      player       = GameState.Instance.PlayerRpgState;
            StatsSet baseStats    = player.BaseStats;
            StatsSet derivedStats = player.DerivedStats;

            //level and XP
            statsSB.AppendFormat("Level {0} ({1}/{2})\n\n", player.Level, player.Experience, RpgValues.XPToNext(player.Level));

            //base statistics
            foreach (StatType value in Enum.GetValues(typeof(StatType)))
            {
                string name = Enum.GetName(typeof(StatType), value);
                if (GameParams.HideStats.Contains(name))
                {
                    continue;
                }
                int baseValue    = baseStats.Stats[value];
                int derivedValue = derivedStats.Stats[value];
                statsSB.AppendFormat("{0}: {1} [{2}]\n", Sub.Replace(name, SubList), baseValue, derivedValue);
            }

            statsSB.AppendLine();

            //damage resistance and threshold
            foreach (int value in Enum.GetValues(typeof(DamageType)))
            {
                string name      = Enum.GetName(typeof(DamageType), value);
                float  baseDR    = baseStats.DamageResistance[(DamageType)value];
                float  baseDT    = baseStats.DamageThreshold[(DamageType)value];
                float  derivedDR = derivedStats.DamageResistance[(DamageType)value];
                float  derivedDT = derivedStats.DamageThreshold[(DamageType)value];
                statsSB.AppendFormat("{0}: DR({1:f1} [{2:f1}]) | DT({3:f1} [{4:f1}])\n", name.Substring(0, Math.Min(4, name.Length)), baseDR, derivedDR, baseDT, derivedDT);
            }

            statsSB.AppendLine();

            //max health
            statsSB.AppendFormat("Max Health: {0:f1} [{1:f1}]", baseStats.MaxHealth, derivedStats.MaxHealth);

            StatsText.text = statsSB.ToString();
        }
예제 #19
0
 void OnEnable()
 {
     //why is this not on SignalPaint? hell if I know
     if (CheckLevelUp && !GameState.Instance.MenuGameStateLocked && GameState.Instance.PlayerRpgState.Experience >= RpgValues.XPToNext(GameState.Instance.PlayerRpgState.Level))
     {
         DefaultLevelUpModal.PushModal(OnLevelUpDone);
     }
 }
예제 #20
0
        public void TakeDamage(ActorHitInfo data)
        {
            LastHit       = null;
            LastHitDamage = 0;

            if (!data.HarmFriendly)
            {
                string hitFaction = data.OriginatorFaction;
                if (!string.IsNullOrEmpty(hitFaction))
                {
                    FactionRelationStatus relation = GameState.Instance.FactionState.GetRelation(hitFaction, Faction); //this looks backwards but it's because we're checking if the Bullet is-friendly-to the Actor
                    if (relation == FactionRelationStatus.Friendly)
                    {
                        return; //no friendly fire
                    }
                }
            }

            ActorDamageHandlerResult?damageHandlerResult = null;

            if (DamageHandler != null)
            {
                damageHandlerResult = DamageHandler(data);
                if (damageHandlerResult.Value.HitInfo.HasValue)
                {
                    data = damageHandlerResult.Value.HitInfo.Value;
                }
                else
                {
                    return;
                }
            }

            LastHit = data;

            float damageTaken;

            if (damageHandlerResult?.DamageTaken != null)
            {
                damageTaken = damageHandlerResult.Value.DamageTaken.Value;
            }
            else
            {
                //new way of doing dr/dt
                float dt = 0, dr = 0;
                foreach (var dNode in DamageResistances)
                {
                    if ((int)dNode.DamageType == data.DamageType)
                    {
                        dt = dNode.DamageThreshold;
                        dr = dNode.DamageResistance;
                    }
                }

                damageTaken = RpgValues.DamageTaken(data, dt, dr);

                if (!data.HitFlags.HasFlag(BuiltinHitFlags.IgnoreHitLocation))
                {
                    if (data.HitLocation == (int)ActorBodyPart.Head)
                    {
                        damageTaken *= 2.0f; //do we want more flexibility here?
                    }
                    else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg)
                    {
                        damageTaken *= 0.75f;
                    }
                }

                damageTaken *= (1f / ConfigState.Instance.GetGameplayConfig().Difficulty.ActorStrength);
            }

            if (!Invincible)
            {
                LastHitDamage = damageTaken;
                Health       -= damageTaken;
            }

            //handle extreme death
            if (damageHandlerResult?.ExtremeDeath != null)
            {
                WasExtremeDeath = damageHandlerResult.Value.ExtremeDeath.Value;
            }
            else
            {
                if (data.HitFlags.HasFlag(BuiltinHitFlags.AlwaysExtremeDeath))
                {
                    WasExtremeDeath = true;
                }
                else if (data.HitFlags.HasFlag(BuiltinHitFlags.NeverExtremeDeath))
                {
                    WasExtremeDeath = false;
                }
                else
                {
                    if (ExtremeDeathThreshold > 0)
                    {
                        //interpret as -(maxhealth * threshold)
                        WasExtremeDeath = Health < (-(MaxHealth * ExtremeDeathThreshold));
                    }
                    else if (ExtremeDeathThreshold < 0)
                    {
                        //interpret as absolute value
                        WasExtremeDeath = Health < ExtremeDeathThreshold;
                    }
                    else
                    {
                        //ExtremeDeathThreshold == 0, no extreme death
                        WasExtremeDeath = false;
                    }
                }
            }

            //TODO do we force into death state here?

            //TODO consider moving this, but probably wait until we start thinking about abuse of corpses
            if (CurrentAiState == ActorAiState.Dead) //abort if we're already dead
            {
                return;
            }

            bool didTakePain;

            if (damageHandlerResult?.TookPain != null)
            {
                didTakePain = damageHandlerResult.Value.TookPain.Value;
            }
            else
            {
                float derivedPainChance = PainChance;
                if (PainGuaranteeThreshold != 0)
                {
                    float damageForMaxPain = Mathf.Abs(PainGuaranteeRelative ? (PainGuaranteeThreshold * MaxHealth) : PainGuaranteeThreshold);
                    derivedPainChance = MathUtils.ScaleRange(damageTaken, 0, damageForMaxPain, PainChance, 1);
                }
                derivedPainChance = Mathf.Min(derivedPainChance, PainMaxChance);

                didTakePain = (data.HitFlags.HasFlag(BuiltinHitFlags.AlwaysPain) || UnityEngine.Random.Range(0f, 1f) < derivedPainChance) && !data.HitFlags.HasFlag(BuiltinHitFlags.NoPain); //TODO shouldn't this be weighted by damage?
            }

            if (Defensive && data.Originator != null && data.Originator != this && !data.HitFlags.HasFlag(BuiltinHitFlags.NeverAlert))
            {
                FactionRelationStatus relation = FactionRelationStatus.Neutral;
                if (data.Originator is PlayerController)
                {
                    relation = GameState.Instance.FactionState.GetRelation(Faction, "Player");
                }
                else if (data.Originator is ActorController)
                {
                    relation = GameState.Instance.FactionState.GetRelation(Faction, ((ActorController)data.Originator).Faction);
                }

                if (relation != FactionRelationStatus.Friendly || Infighting)
                {
                    Target  = data.Originator.transform;
                    BeenHit = true;

                    if (DisableInteractionOnHit && InteractionComponent != null)
                    {
                        InteractionComponent.InteractionDisabledByHit = true;
                    }

                    if (FeelPain && didTakePain && CurrentAiState != ActorAiState.ScriptedAction && CurrentAiState != ActorAiState.ScriptedMoveTo)
                    {
                        if (PainStateAllowRestart || CurrentAiState != ActorAiState.Hurting)
                        {
                            EnterState(ActorAiState.Hurting);
                        }
                    }
                    else if (CurrentAiState != ActorAiState.Chasing && CurrentAiState != ActorAiState.Attacking && CurrentAiState != ActorAiState.ScriptedAction && CurrentAiState != ActorAiState.ScriptedMoveTo)
                    {
                        EnterState(ActorAiState.Chasing);
                    }
                }
                else if ((PainStateAllowRestart || CurrentAiState != ActorAiState.Hurting) && FeelPain && CurrentAiState != ActorAiState.ScriptedAction && CurrentAiState != ActorAiState.ScriptedMoveTo)
                {
                    EnterState(ActorAiState.Hurting);
                }
            }
            else if (FeelPain && didTakePain && (PainStateAllowRestart || CurrentAiState != ActorAiState.Hurting) && CurrentAiState != ActorAiState.ScriptedAction && CurrentAiState != ActorAiState.ScriptedMoveTo)
            {
                EnterState(ActorAiState.Hurting);
            }
        }