public static uint SharedCalculateTotalEnergyCharge(IDynamicWorldObject vehicle) { using var tempItemsList = SharedGetTempListFuelItemsForVehicle(vehicle); return(SharedCalculateTotalEnergyCharge(tempItemsList)); }
private static void ServerCharacterExitVehicleNow(ICharacter character, IDynamicWorldObject vehicle) { if (ServerVehicleQuitRequests.TryGetValue(character, out var requestedVehicleToQuit)) { ServerVehicleQuitRequests.Remove(character); requestedVehicleToQuit.GetPublicState <VehiclePublicState>() .IsDismountRequested = false; } var characterPublicState = PlayerCharacter.GetPublicState(character); if (characterPublicState.CurrentVehicle != vehicle) { return; } InteractableWorldObjectHelper.ServerTryAbortInteraction(character, vehicle); vehicle.GetPublicState <VehiclePublicState>() .IsDismountRequested = false; characterPublicState.ServerSetCurrentVehicle(null); var vehiclePublicState = vehicle.GetPublicState <VehiclePublicState>(); vehiclePublicState.PilotCharacter = null; Logger.Important("Player exit vehicle: " + vehicle, character); if (!vehicle.IsDestroyed) { var characterPrivateState = PlayerCharacter.GetPrivateState(character); characterPrivateState.LastDismountedVehicleMapMark = new LastDismountedVehicleMapMark(vehicle); } character.ProtoWorldObject.SharedCreatePhysics(character); var protoVehicle = (IProtoVehicle)vehicle.ProtoGameObject; if (!vehicle.IsDestroyed) { vehicle.ProtoWorldObject.SharedCreatePhysics(vehicle); // ensure vehicle stopped Server.World.SetDynamicObjectPhysicsMovement(vehicle, Vector2D.Zero, targetVelocity: 0); Server.World.SetDynamicObjectMoveSpeed(vehicle, 0); Server.World.StopPhysicsBody(vehicle.PhysicsBody); // no need to do this here, as it's done automatically by vehicle's ServerUpdate method //protoVehicle.ServerSetUpdateRate(vehicle, isRare: true); protoVehicle.ServerOnCharacterExitVehicle(vehicle, character); } PlayerCharacter.SharedForceRefreshCurrentItem(character); if (vehicle.IsDestroyed) { return; } // notify player and other players in scope using var tempPlayers = Api.Shared.GetTempList <ICharacter>(); Server.World.GetScopedByPlayers(vehicle, tempPlayers); tempPlayers.Remove(character); Instance.CallClient(character, _ => _.ClientRemote_OnVehicleExitByCurrentPlayer(vehicle, protoVehicle)); Instance.CallClient(tempPlayers.AsList(), _ => _.ClientRemote_OnVehicleExitByOtherPlayer(vehicle, vehicle.Position, protoVehicle)); }
/// <summary> /// Try to deduct energy. /// </summary> /// <returns>Returns true if there was enough energy and it was deducted.</returns> public static bool ServerDeductEnergyCharge(IDynamicWorldObject vehicle, ushort requiredEnergyAmount) { return(ServerDeductEnergyChargeInternal(vehicle, requiredEnergyAmount)); }
public static void ServerUnregisterCurrentMining(IDynamicWorldObject droneObject) { ServerCurrentMinedObjectsByDrones.RemoveAllByValue( existingDroneObject => ReferenceEquals(existingDroneObject, droneObject)); }
public ViewModelVehicleNameEditorControl(IDynamicWorldObject vehicle) { this.vehicle = vehicle; this.Name = VehicleNamesSystem.ClientTryGetVehicleName(vehicle.Id) ?? string.Empty; }
public static void NotifyObjectDestroyed(ICharacter character, IDynamicWorldObject worldObject) { Api.SafeInvoke(() => ObjectDestroyed?.Invoke(character, worldObject)); }
public virtual float SharedGetStructurePointsMax(IDynamicWorldObject worldObject) { return(this.StructurePointsMax); }
public WeaponFinalCache( ICharacter character, FinalStatsCache characterFinalStatsCache, [CanBeNull] IItem weapon, [CanBeNull] IProtoItemWeapon protoWeapon, [CanBeNull] IProtoItemAmmo protoAmmo, DamageDescription damageDescription, IProtoExplosive protoExplosive = null, IDynamicWorldObject objectDrone = null) { this.Character = character; this.CharacterFinalStatsCache = characterFinalStatsCache; this.Drone = objectDrone; this.Weapon = weapon; this.ProtoWeapon = (IProtoItemWeapon)weapon?.ProtoItem ?? protoWeapon; this.ProtoAmmo = protoAmmo; this.ProtoExplosive = protoExplosive; if (damageDescription is null) { // TODO: it looks like not implemented yet and we should throw an exception here // fallback in case weapon don't provide damage description (such as no-ammo weapon) damageDescription = new DamageDescription( damageValue: 0, armorPiercingCoef: 0, finalDamageMultiplier: 1, rangeMax: 0, damageDistribution: new DamageDistribution()); } var descriptionDamages = damageDescription.DamageProportions; var damageDistributionsCount = descriptionDamages.Count; var resultDamageDistributions = new List <DamageProportion>(damageDistributionsCount); var totalPercents = 0d; for (var index = 0; index < damageDistributionsCount; index++) { var source = descriptionDamages[index]; var statName = GetProportionStatName(source.DamageType); var resultDamageProportion = source.Proportion + characterFinalStatsCache[statName]; if (resultDamageProportion <= 0) { continue; } resultDamageDistributions.Add(new DamageProportion(source.DamageType, resultDamageProportion)); totalPercents += resultDamageProportion; } if (damageDistributionsCount > 0 && Math.Abs(totalPercents - 1) > 0.001d) { throw new Exception( "Sum of all damage proportions must be exactly 1. Calculated value: " + totalPercents.ToString("F3")); } this.DamageDistributions = resultDamageDistributions; this.DamageValue = damageDescription.DamageValue * (protoWeapon?.DamageMultiplier ?? 1.0) + characterFinalStatsCache[StatName.DamageAdd]; var weaponSkillProto = protoWeapon?.WeaponSkillProto; if (weaponSkillProto is not null) { var statName = protoWeapon.WeaponSkillProto.StatNameDamageBonusMultiplier; this.DamageValue *= characterFinalStatsCache.GetMultiplier(statName); } this.RangeMax = damageDescription.RangeMax * (protoWeapon?.RangeMultiplier ?? 1.0) + characterFinalStatsCache[StatName.AttackRangeMax]; var armorPiercingCoef = (1 + characterFinalStatsCache[StatName.AttackArmorPiercingMultiplier]) * (damageDescription.ArmorPiercingCoef + characterFinalStatsCache[StatName.AttackArmorPiercingValue]); this.InvertedArmorPiercingCoef = 1 - armorPiercingCoef; this.FinalDamageMultiplier = damageDescription.FinalDamageMultiplier + characterFinalStatsCache[StatName.AttackFinalDamageMultiplier]; var probability = protoWeapon?.SpecialEffectProbability ?? 0; if (weaponSkillProto is not null) { var statNameSpecialEffectChance = weaponSkillProto.StatNameSpecialEffectChanceMultiplier; probability *= characterFinalStatsCache.GetMultiplier(statNameSpecialEffectChance); } this.SpecialEffectProbability = probability; this.FireScatterPreset = protoAmmo?.OverrideFireScatterPreset ?? protoWeapon?.FireScatterPreset ?? default; var shotsPerFire = this.FireScatterPreset.ProjectileAngleOffets.Length; if (shotsPerFire > 1) { // decrease final damage and special effect multiplier on the number of shots per fire var coef = 1.0 / shotsPerFire; this.FinalDamageMultiplier *= coef; this.SpecialEffectProbability *= coef; } }
public override IItemsContainer SharedGetHotbarItemsContainer(IDynamicWorldObject vehicle) { return(GetPrivateState(vehicle).EquipmentItemsContainer); }
public void ServerSetupAssociatedItem(IDynamicWorldObject objectDrone, IItem item) { GetPrivateState(objectDrone).AssociatedItem = item; }
private static void ServerOnDroneReturnedToPlayer(IDynamicWorldObject worldObject) { var privateState = GetPrivateState(worldObject); var character = privateState.CharacterOwner; CharacterDroneControlSystem.ServerDespawnDrone(worldObject, isReturnedToPlayer: true); var storageContainer = privateState.StorageItemsContainer; if (storageContainer.OccupiedSlotsCount == 0) { return; } // drop storage container contents to player // but first, move the drone item to its original slot (if possible) var characterContainerInventory = character.SharedGetPlayerContainerInventory(); var characterContainerHotbar = character.SharedGetPlayerContainerHotbar(); var itemInFirstSlot = storageContainer.GetItemAtSlot(0); if (itemInFirstSlot != null) { // item in the first slot is the drone's associated item // it could be destroyed in case the drone's HP dropped <= 1 Server.Items.MoveOrSwapItem(itemInFirstSlot, privateState.IsStartedFromHotbarContainer ? characterContainerHotbar : characterContainerInventory, slotId: privateState.StartedFromSlotIndex, movedCount: out _); } var result = Server.Items.TryMoveAllItems(storageContainer, characterContainerInventory); try { if (storageContainer.OccupiedSlotsCount == 0) { // all items moved from drone to player return; } // try move remaining items to hotbar var resultToHotbar = Server.Items.TryMoveAllItems(storageContainer, characterContainerHotbar); result.MergeWith(resultToHotbar, areAllItemsMoved: resultToHotbar.AreAllItemMoved); if (storageContainer.OccupiedSlotsCount == 0) { // all items moved from drone to player return; } } finally { if (result.MovedItems.Count > 0) { // notify player about the received items NotificationSystem.ServerSendItemsNotification( character, result.MovedItems .GroupBy(p => p.Key.ProtoItem) .Where(p => !(p.Key is TItemDrone)) .ToDictionary(p => p.Key, p => p.Sum(v => v.Value))); } } // try to drop the remaining items on the ground var groundContainer = ObjectGroundItemsContainer .ServerTryGetOrCreateGroundContainerAtTileOrNeighbors(character, character.Tile); if (groundContainer != null) { var protoItemForIcon = storageContainer.Items.First().ProtoItem; Server.Items.TryMoveAllItems(storageContainer, groundContainer); NotificationSystem.ServerSendNotificationNoSpaceInInventoryItemsDroppedToGround(character, protoItemForIcon); // ensure that these items could be lifted only by their owner in PvE WorldObjectClaimSystem.ServerTryClaim(groundContainer.OwnerAsStaticObject, character, WorldObjectClaimDuration.DroppedGoods); } if (storageContainer.OccupiedSlotsCount == 0) { return; } Logger.Error("Not all items dropped on the ground from the drone storage: " + worldObject + " slots occupied: " + storageContainer.OccupiedSlotsCount); }
public override void ServerOnDestroy(IDynamicWorldObject gameObject) { base.ServerOnDestroy(gameObject); CharacterDroneControlSystem.ServerOnDroidDestroyed(gameObject); }
public IItemsContainer ServerGetStorageItemsContainer(IDynamicWorldObject objectDrone) { return(GetPrivateState(objectDrone).StorageItemsContainer); }
protected virtual void ClientSetupEngineAudio( IDynamicWorldObject vehicle, ComponentHoverboardEngineSoundEmitter component) { }
public static bool SharedHasEnergyCharge(IDynamicWorldObject vehicle, uint energyRequired) { using var tempItemsList = SharedGetTempListFuelItemsForVehicle(vehicle); return(SharedHasEnergyCharge(tempItemsList, energyRequired)); }
public HUDMechHotbarControl(IDynamicWorldObject vehicle) { this.vehicle = vehicle; }
public ViewModelWindowObjectVehicle( IDynamicWorldObject vehicle, FrameworkElement vehicleExtraControl, IViewModelWithActiveState vehicleExtraControlViewModel) { this.VehicleExtraControl = vehicleExtraControl; this.VehicleExtraControlViewModel = vehicleExtraControlViewModel; if (vehicleExtraControl is not null) { vehicleExtraControl.DataContext = vehicleExtraControlViewModel; } var currentCharacter = Api.Client.Characters.CurrentPlayerCharacter; this.ContainerPlayerInventory = (IClientItemsContainer)currentCharacter.SharedGetPlayerContainerInventory(); this.ProtoVehicle = (IProtoVehicle)vehicle.ProtoGameObject; this.vehiclePublicState = vehicle.GetPublicState <VehiclePublicState>(); this.vehiclePrivateState = vehicle.GetPrivateState <VehiclePrivateState>(); var structurePointsMax = this.ProtoVehicle.SharedGetStructurePointsMax(vehicle); this.ViewModelStructurePoints = new ViewModelStructurePointsBarControl() { ObjectStructurePointsData = new ObjectStructurePointsData(vehicle, structurePointsMax) }; this.ViewModelVehicleEnergy = new ViewModelVehicleEnergy(vehicle); this.cargoItemsContainer = this.vehiclePrivateState.CargoItemsContainer as IClientItemsContainer; this.ViewModelItemsContainerExchange = new ViewModelItemsContainerExchange(this.cargoItemsContainer, callbackTakeAllItemsSuccess: null) { IsContainerTitleVisible = false }; this.ViewModelItemsContainerExchange.IsActive = false; var isOwner = WorldObjectOwnersSystem.SharedIsOwner( ClientCurrentCharacterHelper.Character, vehicle); this.ViewModelOwnersEditor = new ViewModelWorldObjectOwnersEditor(this.vehiclePrivateState.Owners, canEditOwners: isOwner || CreativeModeSystem.ClientIsInCreativeMode(), callbackServerSetOwnersList: ownersList => WorldObjectOwnersSystem.ClientSetOwners( vehicle, ownersList), title: CoreStrings.ObjectOwnersList_Title2); this.RefreshCanRepair(); this.IsVehicleTabActive = true; this.ViewModelItemsContainerExchange.IsActive = true; if (this.cargoItemsContainer is not null) { this.cargoItemsContainer.ItemAdded += this.CargoItemsContainerItemAddedHandler; this.cargoItemsContainer.ItemCountChanged += this.CargoItemsContainerItemCountChangedHandler; } }
public static void ServerRecallDrone(IDynamicWorldObject objectDrone) { objectDrone.GetPublicState <DronePublicState>() .ResetTargetPosition(); ServerUnregisterCurrentMining(objectDrone); }
protected virtual void ServerOnDynamicObjectDestroyedByCharacter( [CanBeNull] ICharacter byCharacter, [CanBeNull] IProtoItemWeapon byWeaponProto, IDynamicWorldObject targetObject) { }
private static void SharedShotWeaponHitscan( ICharacter character, IProtoItemWeapon protoWeapon, Vector2D fromPosition, WeaponFinalCache weaponCache, Vector2D?customTargetPosition, IProtoCharacterCore characterProtoCharacter, double fireSpreadAngleOffsetDeg, CollisionGroup collisionGroup, bool isMeleeWeapon, IDynamicWorldObject characterCurrentVehicle, ProtoSkillWeapons protoWeaponSkill, PlayerCharacterSkills playerCharacterSkills, ITempList <IWorldObject> allHitObjects) { Vector2D toPosition; var rangeMax = weaponCache.RangeMax; if (customTargetPosition.HasValue) { var direction = customTargetPosition.Value - fromPosition; // ensure the max range is not exceeded direction = direction.ClampMagnitude(rangeMax); toPosition = fromPosition + direction; } else { toPosition = fromPosition + new Vector2D(rangeMax, 0) .RotateRad(characterProtoCharacter.SharedGetRotationAngleRad(character) + fireSpreadAngleOffsetDeg * Math.PI / 180.0); } using var lineTestResults = character.PhysicsBody.PhysicsSpace.TestLine( fromPosition: fromPosition, toPosition: toPosition, collisionGroup: collisionGroup); var damageMultiplier = 1d; var hitObjects = new List <WeaponHitData>(isMeleeWeapon ? 1 : lineTestResults.Count); var characterTileHeight = character.Tile.Height; if (IsClient || Api.IsEditor) { SharedEditorPhysicsDebugger.SharedVisualizeTestResults(lineTestResults, collisionGroup); } var isDamageRayStopped = false; foreach (var testResult in lineTestResults.AsList()) { var testResultPhysicsBody = testResult.PhysicsBody; var attackedProtoTile = testResultPhysicsBody.AssociatedProtoTile; if (attackedProtoTile != null) { if (attackedProtoTile.Kind != TileKind.Solid) { // non-solid obstacle - skip continue; } var attackedTile = IsServer ? Server.World.GetTile((Vector2Ushort)testResultPhysicsBody.Position) : Client.World.GetTile((Vector2Ushort)testResultPhysicsBody.Position); if (attackedTile.Height < characterTileHeight) { // attacked tile is below - ignore it continue; } // tile on the way - blocking damage ray isDamageRayStopped = true; var hitData = new WeaponHitData(testResult.PhysicsBody.Position + SharedOffsetHitWorldPositionCloserToTileHitboxCenter( testResultPhysicsBody, testResult.Penetration, isRangedWeapon: !isMeleeWeapon)); hitObjects.Add(hitData); weaponCache.ProtoWeapon .SharedOnHit(weaponCache, null, 0, hitData, out _); break; } var damagedObject = testResultPhysicsBody.AssociatedWorldObject; if (ReferenceEquals(damagedObject, character) || ReferenceEquals(damagedObject, characterCurrentVehicle)) { // ignore collision with self continue; } if (!(damagedObject.ProtoGameObject is IDamageableProtoWorldObject damageableProto)) { // shoot through this object continue; } // don't allow damage is there is no direct line of sight on physical colliders layer between the two objects if (SharedHasTileObstacle(character.Position, characterTileHeight, damagedObject, targetPosition: testResult.PhysicsBody.Position + testResult.PhysicsBody.CenterOffset)) { continue; } using (CharacterDamageContext.Create(attackerCharacter: character, damagedObject as ICharacter, protoWeaponSkill)) { if (!damageableProto.SharedOnDamage( weaponCache, damagedObject, damageMultiplier, damagePostMultiplier: 1.0, out var obstacleBlockDamageCoef, out var damageApplied)) { // not hit continue; } var hitData = new WeaponHitData(damagedObject, testResult.Penetration.ToVector2F()); weaponCache.ProtoWeapon .SharedOnHit(weaponCache, damagedObject, damageApplied, hitData, out var isDamageStop); if (isDamageStop) { obstacleBlockDamageCoef = 1; } if (IsServer) { if (damageApplied > 0 && damagedObject is ICharacter damagedCharacter) { CharacterUnstuckSystem.ServerTryCancelUnstuckRequest(damagedCharacter); } if (damageApplied > 0) { // give experience for damage protoWeaponSkill?.ServerOnDamageApplied(playerCharacterSkills, damagedObject, damageApplied); } } if (obstacleBlockDamageCoef < 0 || obstacleBlockDamageCoef > 1) { Logger.Error( "Obstacle block damage coefficient should be >= 0 and <= 1 - wrong calculation by " + damageableProto); break; } hitObjects.Add(hitData); if (isMeleeWeapon) { // currently melee weapon could attack only one object on the ray isDamageRayStopped = true; break; } damageMultiplier *= 1.0 - obstacleBlockDamageCoef; if (damageMultiplier <= 0) { // target blocked the damage ray isDamageRayStopped = true; break; } } } var shotEndPosition = GetShotEndPosition(isDamageRayStopped, hitObjects, toPosition, isRangedWeapon: !isMeleeWeapon); if (hitObjects.Count == 0) { protoWeapon.SharedOnMiss(weaponCache, shotEndPosition); } SharedCallOnWeaponHitOrTrace(character, protoWeapon, weaponCache.ProtoAmmo, shotEndPosition, hitObjects, endsWithHit: isDamageRayStopped); foreach (var entry in hitObjects) { if (!entry.IsCliffsHit && !allHitObjects.Contains(entry.WorldObject)) { allHitObjects.Add(entry.WorldObject); } } }