private void ServerTimerTick() { const double experienceToAdd = ExperienceAddWhenOnlinePerSecond * TimerIntervalSeconds; foreach (var character in Server.Characters.EnumerateAllPlayerCharacters(onlyOnline: true)) { if (character.ProtoCharacter.GetType() != typeof(PlayerCharacter)) { // only characters of specific type (PlayerCharacter) are processed continue; } var publicState = PlayerCharacter.GetPublicState(character); if (publicState.IsDead) { // dead characters are not processed continue; } if (CharacterIdleSystem.ServerIsIdlePlayer(character)) { // idle character continue; } character.ServerAddSkillExperience(this, experienceToAdd); } }
protected override void ServerUpdate(StatusEffectData data) { var character = data.Character; if (!character.ServerIsOnline) { // only online characters are affected by thirst return; } if (!IsLowWater(character)) { // not thirsty anymore character.ServerRemoveStatusEffect(this); return; } if (CharacterIdleSystem.ServerIsIdlePlayer(character)) { return; } // reduce character health var stats = data.CharacterCurrentStats; stats.ServerReduceHealth(DamagePerSecond * data.DeltaTime, data.StatusEffect); }
protected sealed override void ServerUpdate(ServerUpdateData data) { base.ServerUpdate(data); if (this.durabilityDecreasePerServerUpdate <= 0) { // non-degradeable return; } if (data.DeltaTime <= 0) { // not processed return; } // try to degrade durability over time and give experience for cybernetic affinity skill var item = data.GameObject; var owner = item.Container?.OwnerAsCharacter; if (owner is null || !owner.ServerIsOnline || owner.SharedGetPlayerContainerEquipment() != item.Container) { // player offline or not an equipped item return; } if (CharacterIdleSystem.ServerIsIdlePlayer(owner)) { return; } var durabilityDecrease = this.durabilityDecreasePerServerUpdate; durabilityDecrease *= owner.SharedGetFinalStatMultiplier(StatName.ImplantDegradationSpeedMultiplier); ItemDurabilitySystem.ServerModifyDurability(item, -durabilityDecrease, roundUp: false); owner.ServerAddSkillExperience <SkillCyberneticAffinity>( data.DeltaTime * SkillCyberneticAffinity.ExperienceAddedPerImplantPerSecond); if (!item.IsDestroyed) { this.ServerUpdateInstalledImplant(data); } }
public void ServerOnSkillExperienceAdded( ICharacter character, double experienceAdded, byte currentLevel) { var multiplier = this.ExperienceToLearningPointsConversionMultiplier * TechConstants.ServerSkillExperienceToLearningPointsConversionMultiplier; // apply reversed experience gain multiplier so faster/slower skill exp gain speed will not affect LP gain speed multiplier /= TechConstants.ServerSkillExperienceGainMultiplier; if (multiplier <= 0 || double.IsNaN(multiplier)) { return; } // reduce LP gain proportionally to the skill level var lpRateMultiplier = MathHelper.Lerp(1, TechConstants.SkillLearningPointMultiplierAtMaximumLevel, currentLevel / (double)this.MaxLevel); multiplier *= lpRateMultiplier; if (multiplier <= 0) { return; } var learningPointsToAdd = experienceAdded * multiplier; var partyMembersNames = this.IsSharingLearningPointsWithPartyMembers ? PartySystem.ServerGetPartyMembersReadOnly(character) : Array.Empty <string>(); if (partyMembersNames.Count <= 1) { // no experience share, no party or a single member party - add all LP to the current character character.SharedGetTechnologies() .ServerAddLearningPoints(learningPointsToAdd); return; } using var onlinePartyMembers = Api.Shared.GetTempList <ICharacter>(); foreach (var partyMemberName in partyMembersNames) { var partyMember = Server.Characters.GetPlayerCharacter(partyMemberName); if (partyMember is null) { continue; } if (ReferenceEquals(partyMember, character) || (partyMember.ServerIsOnline && !CharacterIdleSystem.ServerIsIdlePlayer(partyMember))) { onlinePartyMembers.Add(partyMember); } } if (onlinePartyMembers.Count <= 1 || PartyConstants.PartyLearningPointsSharePercent == 0) { // no party, or a single member party, or no party share % // - add all LP to the current character character.SharedGetTechnologies() .ServerAddLearningPoints(learningPointsToAdd); return; } // player has a party // add only a share of LP to current character var currentCharacterLearningPointsShare = learningPointsToAdd * (1 - PartyConstants.PartyLearningPointsSharePercent); character.SharedGetTechnologies() .ServerAddLearningPoints(currentCharacterLearningPointsShare); // distribute the rest equally to the other party members var learningPointsShare = learningPointsToAdd * PartyConstants.PartyLearningPointsSharePercent / (onlinePartyMembers.Count - 1); foreach (var partyMember in onlinePartyMembers.AsList()) { if (!ReferenceEquals(partyMember, character)) { partyMember.SharedGetTechnologies() .ServerAddLearningPoints(learningPointsShare); } } }
private bool ServerCheckIsDoorShouldBeOpened( IStaticWorldObject worldObject, TPrivateState privateState) { if (privateState.IsBlockedByShield) { return(false); } var mode = privateState.AccessMode; if (mode == WorldObjectAccessMode.Closed) { return(false); } Server.World.GetInViewScopeByPlayers(worldObject, StaticTempCharactersNearby); if (StaticTempCharactersNearby.Count == 0) { // no characters nearby return(false); } var objectOpeningBounds = this.SharedGetDoorOpeningBounds(worldObject); foreach (var character in StaticTempCharactersNearby) { if (!character.ServerIsOnline || CharacterIdleSystem.ServerIsIdlePlayer(character) || character.ProtoCharacter is PlayerCharacterSpectator) { continue; } if (!objectOpeningBounds.Contains(character.Position)) { // too far from this door continue; } if (!WorldObjectAccessModeSystem.ServerHasAccess(worldObject, character, mode, writeToLog: false)) { continue; } // we don't do this check because it requires character to be the door owner //if (!this.SharedCanInteract(character, gameObject, writeToLog: false)) //{ // return false; //} // we do this check instead: // ensure the character is alive and there is a direct line of sight between the character and the door var characterPublicState = character.GetPublicState <ICharacterPublicState>(); if (characterPublicState.IsDead) { // dead continue; } if (!this.IsHeavyVehicleCanPass && characterPublicState is PlayerCharacterPublicState playerCharacterPublicState && playerCharacterPublicState.CurrentVehicle?.ProtoGameObject is IProtoVehicle protoVehicle && protoVehicle.IsHeavyVehicle) { // in a heavy vehicle and cannot pass continue; } var characterPhysicsBody = character.PhysicsBody; var characterCenter = character.Position + characterPhysicsBody.CenterOffset; if (!ObstacleTestHelper.SharedHasObstaclesOnTheWay(characterCenter, characterPhysicsBody.PhysicsSpace, worldObject, sendDebugEvents: true)) { return(true); } } // the door should be closed return(false); }