Пример #1
0
        private void SelectRandomEntries(ITempList <Entry> result)
        {
            var countToSelect = this.Outputs + RandomHelper.Next(0, this.OutputsRandom + 1);

            if (countToSelect >= this.frozenEntries.Count)
            {
                // simply return all the entries
                foreach (var entry in this.entries)
                {
                    result.Add(entry.Value);
                }

                return;
            }

            if (countToSelect == 1)
            {
                // simply return a single random selected entry
                result.Add(this.frozenEntries.GetSingleRandomElement());
                return;
            }

            // need to select multiple random entries
            // ReSharper disable once SuspiciousTypeConversion.Global
            this.frozenEntries.SelectRandomElements((List <Entry>)result, countToSelect);
        }
 private static void SharedFindPowerBanks(IItemsContainer container, ITempList <IItem> tempList)
 {
     foreach (var item in container.Items)
     {
         if (item.ProtoItem is IProtoItemPowerBank)
         {
             tempList.Add(item);
         }
     }
 }
Пример #3
0
        protected virtual void ClientFillSlotAttachmentSources(ITempList <string> folders)
        {
            var baseProtoItem = this.BaseProtoItem;

            if (baseProtoItem is not null)
            {
                folders.Add(
                    $"Characters/Equipment/{baseProtoItem.ShortId}/{this.ShortId.Substring(baseProtoItem.ShortId.Length)}");
                return;
            }

            var path = $"Characters/Equipment/{this.ShortId}/Default";

            if (Api.Shared.IsFolderExists(ContentPaths.Textures + path))
            {
                folders.Add(path);
                return;
            }

            folders.Add($"Characters/Equipment/{this.ShortId}");
        }
Пример #4
0
        public static void SharedGetAreasInBounds(RectangleInt bounds, ITempList <ILogicObject> result)
        {
            if (result.Count > 0)
            {
                result.Clear();
            }

            // TODO: the lookup is really slow on the populated servers. Consider Grid or QuadTree optimization to locate areas quickly.
            foreach (var area in sharedLandClaimAreas)
            {
                var areaBounds = SharedGetLandClaimAreaBounds(area);
                if (areaBounds.IntersectsLoose(bounds))
                {
                    result.Add(area);
                }
            }
        }
Пример #5
0
        private void SelectRandomEntries(ITempList <Entry> result, DropItemContext dropItemContext)
        {
            var countToSelect = this.Outputs + RandomHelper.Next(0, this.OutputsRandom + 1);

            if (countToSelect >= this.frozenEntries.Count)
            {
                // simply return all the entries
                foreach (var entry in this.entries)
                {
                    result.Add(entry.Value);
                }

                return;
            }

            if (countToSelect == 1)
            {
                // simply return a single random selected entry that is satisfying the condition
                Entry entry = default;
                for (var attempt = 0; attempt < 100; attempt++)
                {
                    entry = this.frozenEntries.GetSingleRandomElement();
                    if (entry.Condition is null)
                    {
                        break;
                    }

                    try
                    {
                        if (entry.Condition(dropItemContext))
                        {
                            break;
                        }

                        // condition not match, select another entry
                        continue;
                    }
                    catch (Exception ex)
                    {
                        Api.Logger.Exception(ex, "Exception during checking condition for droplist item " + entry);
                        break;
                    }
                }

                if (!entry.Equals(default))
 protected virtual void ClientFillSlotAttachmentSources(ITempList <string> folders)
 {
     folders.Add("Characters/Equipment/" + this.ShortId);
 }
Пример #7
0
 protected override void ClientFillSlotAttachmentSources(ITempList <string> folders)
 {
     base.ClientFillSlotAttachmentSources(folders);
     // add generic pants
     folders.Add("Characters/Equipment/GenericPants");
 }
Пример #8
0
        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);
                }
            }
        }