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); } }
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; }
void OnEnable() { if (CheckLevelUp && GameState.Instance.PlayerRpgState.Experience >= RpgValues.XPToNext(GameState.Instance.PlayerRpgState.Level)) { DefaultLevelUpModal.PushModal(OnLevelUpDone); } }
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); } }
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); }
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); } }
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); } }
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; } }
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); } }
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); }
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); } }
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; } }
//on actual level handler public void OnClickLevelUp() { NewStats.Skills[(SkillType)SelectedSkill] = NewStats.Skills[(SkillType)SelectedSkill] + RpgValues.SkillGainForPoints(1); PotentialPoints--; UpdateValues(); }
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); }
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); }
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(); }
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")); } }
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(); }
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); } }
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); } }