Beispiel #1
0
        public SpellData(string name, IniBin ini)
        {
            var enumTranslationService = new EnumTranslationService();

            Name      = name;
            Flags     = (SpellFlags)(ini["SpellData", "Flags"].Int() ?? 0);
            TextFlags = ini["SpellData", "TextFlags"].String() ?? "";

            var cooldownTime            = new Dictionary <int, float>(7);
            var maxAmmo                 = new Dictionary <int, int>(7);
            var ammoUsed                = new Dictionary <int, int>(7);
            var ammoRechargeTime        = new Dictionary <int, float>(7);
            var castRange               = new Dictionary <int, float>(7);
            var channelDuration         = new Dictionary <int, float>(7);
            var castRangeGrowthMax      = new Dictionary <int, float>(7);
            var castRangeGrowthDuration = new Dictionary <int, float>(7);
            var castRadius              = new Dictionary <int, float>(7);
            var castRadiusSecondary     = new Dictionary <int, float>(7);
            var mana = new Dictionary <int, float>(7);


            cooldownTime[0]            = ini["SpellData", "Cooldown"].Float() ?? 10.0f;
            maxAmmo[0]                 = ini["SpellData", "MaxAmmo"].Int() ?? 0;
            ammoUsed[0]                = ini["SpellData", "AmmoUsed"].Int() ?? 1;
            ammoRechargeTime[0]        = ini["SpellData", "AmmoRechargeTime"].Float() ?? 0.0f;
            channelDuration[0]         = ini["SpellData", "ChannelDuration"].Float() ?? 0.0f;
            castRange[0]               = ini["SpellData", "CastRange"].Float() ?? 400.0f;
            castRangeGrowthMax[0]      = ini["SpellData", "CastRangeGrowthMax"].Float() ?? 0.0f;
            castRangeGrowthDuration[0] = ini["SpellData", "CastRangeGrowthDuration"].Float() ?? 0.0f;
            castRadius[0]              = ini["SpellData", "CastRadius"].Float() ?? 0.0f;
            castRadiusSecondary[0]     = ini["SpellData", "CastRadiusSecondary"].Float() ?? 0.0f;
            mana[0] = ini["SpellData", "ManaCost1"].Float() ?? 0.0f;

            for (var i = 1; i < 7; i++)
            {
                cooldownTime[i]            = ini["SpellData", $"Cooldown{i}"].Float() ?? cooldownTime[0];
                maxAmmo[i]                 = ini["SpellData", $"MaxAmmo{i}"].Int() ?? maxAmmo[0];
                ammoUsed[i]                = ini["SpellData", $"AmmoUsed{i}"].Int() ?? ammoUsed[0];
                ammoRechargeTime[i]        = ini["SpellData", $"AmmoRechargeTime{i}"].Float() ?? ammoRechargeTime[0];
                channelDuration[i]         = ini["SpellData", $"ChannelDuration{i}"].Float() ?? channelDuration[0];
                castRange[i]               = ini["SpellData", $"CastRange{i}"].Float() ?? castRange[0];
                castRangeGrowthMax[i]      = ini["SpellData", $"CastRangeGrowthMax{i}"].Float() ?? castRangeGrowthMax[0];
                castRangeGrowthDuration[i] = ini["SpellData", $"CastRangeGrowthDuration{i}"].Float() ?? castRangeGrowthDuration[0];
                castRadius[i]              = ini["SpellData", $"CastRadius{i}"].Float() ?? castRadius[0];
                castRadiusSecondary[i]     = ini["SpellData", $"CastRadiusSecondary{i}"].Float() ?? castRadiusSecondary[0];
                mana[i] = ini["SpellData", $"ManaCost{i}"].Float() ?? mana[0];
            }

            CooldownTime            = cooldownTime;
            MaxAmmo                 = maxAmmo;
            AmmoUsed                = ammoUsed;
            AmmoRechargeTime        = ammoRechargeTime;
            ChannelDuration         = channelDuration;
            CastRange               = castRange;
            CastRangeGrowthMax      = castRangeGrowthMax;
            CastRangeGrowthDuration = castRangeGrowthDuration;
            CastRadius              = castRadius;
            CastRadiusSecondary     = castRadiusSecondary;
            Mana = mana;

            var totalTime = ini["SpellData", "SpellTotalTime"].Float() ?? 0.0f;
            var castTime  = ini["SpellData", "SpellCastTime"].Float() ?? 0.0f;

            castTime = Math.Min(castTime, totalTime);
            if (totalTime > 0.0f && castTime > 0.0f)
            {
                SpellTotalTime = totalTime;
                SpellCastTime  = castTime;
            }
            else
            {
                var delayTotalPercent = ini["SpellData", "DelayTotalTimePercent"].Float() ?? 0.0f;
                var delayCastPercent  = ini["SpellData", "DelayCastOffsetPercent"].Float() ?? 0.0f;
                SpellTotalTime = (delayTotalPercent + 1.0f) * 2.0f;
                SpellCastTime  = (delayCastPercent + 1.0f) * 0.5f;
            }
            OverrideCastTime                = ini["SpellData", "OverrideCastTime"].Float() ?? 0.0f;
            StartCooldown                   = ini["SpellData", "StartCooldown"].Float() ?? 0.0f;
            ChargeUpdateInterval            = ini["SpellData", "ChargeUpdateInterval"].Float() ?? 0.0f;
            CancelChargeOnRecastTime        = ini["SpellData", "CancelChargeOnRecastTime"].Float() ?? 0.0f;
            CastConeAngle                   = ini["SpellData", "CastConeAngle"].Float() ?? 45.0f;
            CastConeDistance                = ini["SpellData", "CastConeDistance"].Float() ?? 400.0f;
            CastTargetAdditionalUnitsRadius = ini["SpellData", "CastTargetAdditionalUnitsRadius"].Float() ?? 0.0f;
            CastFrame           = ini["SpellData", "CastFrame"].Float() ?? 0.0f;
            LineWidth           = ini["SpellData", "LineWidth"].Float() ?? 0.0f;
            LineDragLength      = ini["SpellData", "LineDragLength"].Float() ?? 0.0f;
            LookAtPolicy        = enumTranslationService.TranslateLookAtPolicy(ini["SpellData", "LookAtPolicy"].StringEnum <LookAtPolicy>() ?? LeagueData.LookAtPolicy.Automatic);
            SelectionPreference = enumTranslationService.TranslateSelectionPreference(ini["SpellData", "SelectionPreference"].StringEnum <SelectionPreference>() ?? LeagueData.SelectionPreference.None);
            TargetingType       = enumTranslationService.TranslateTargetingType((TargetingType)(ini["SpellData", "TargettingType"].Int() ?? 1));

            CastRangeUseBoundingBoxes        = ini["SpellData", "CastRangeUseBoundingBoxes"].IntBool() ?? false;
            AmmoNotAffectedByCDR             = ini["SpellData", "AmmoNotAffectedByCDR"].Bool() ?? false;
            UseAutoattackCastTime            = ini["SpellData", "UseAutoattackCastTime"].Bool() ?? false;
            IgnoreAnimContinueUntilCastFrame = ini["SpellData", "IgnoreAnimContinueUntilCastFrame"].Bool() ?? false;
            IsToggleSpell             = ini["SpellData", "IsToggleSpell"].Bool() ?? false;
            CanNotBeSuppressed        = ini["SpellData", "CanNotBeSuppressed"].Bool() ?? false;
            CanCastWhileDisabled      = ini["SpellData", "CanCastWhileDisabled"].Bool() ?? false;
            CanOnlyCastWhileDisabled  = ini["SpellData", "CanOnlyCastWhileDisabled"].Bool() ?? false;
            CantCancelWhileWindingUp  = ini["SpellData", "CantCancelWhileWindingUp"].Bool() ?? false;
            CantCancelWhileChanneling = ini["SpellData", "CantCancelWhileChanneling"].Bool() ?? false;
            CantCastWhileRooted       = ini["SpellData", "CantCastWhileRooted"].Bool() ?? false;
            DoesntBreakChannels       = ini["SpellData", "DoesntBreakChannels"].Bool() ?? false;
            IsDisabledWhileDead       = ini["SpellData", "IsDisabledWhileDead"].Bool() ?? true;
            CanOnlyCastWhileDead      = ini["SpellData", "CanOnlyCastWhileDead"].Bool() ?? false;
            SpellRevealsChampion      = ini["SpellData", "SpellRevealsChampion"].IntBool() ?? true;
            UseChargeChanneling       = ini["SpellData", "UseChargeChanneling"].Bool() ?? false;
            UseChargeTargeting        = ini["SpellData", "UseChargeTargeting"].Bool() ?? false;
            CanMoveWhileChanneling    = ini["SpellData", "CanMoveWhileChanneling"].Bool() ?? false;
            DoNotNeedToFaceTarget     = ini["SpellData", "DoNotNeedToFaceTarget"].Bool() ?? false;
            NoWinddownIfCancelled     = ini["SpellData", "NoWinddownIfCancelled"].Bool() ?? false;
            IgnoreRangeCheck          = ini["SpellData", "IgnoreRangeCheck"].Bool() ?? false;
            ConsideredAsAutoAttack    = ini["SpellData", "ConsideredAsAutoAttack"].Bool() ?? false;
            ApplyAttackDamage         = ini["SpellData", "ApplyAttackDamage"].Bool() ?? false;
            ApplyAttackEffect         = ini["SpellData", "ApplyAttackEffect"].Bool() ?? false;
            AlwaysSnapFacing          = ini["SpellData", "AlwaysSnapFacing"].Bool() ?? false;
            BelongsToAvatar           = ini["SpellData", "BelongsToAvatar"].Bool() ?? false;

            CastType = enumTranslationService.TranslateCastType((LeagueData.CastType)(ini["SpellData", "CastType"].Int() ?? 0));
            if (CastType == LeagueSandbox.GameServer.Core.Domain.Enums.CastType.Instant)
            {
                CastData = new CastData.Instant();
            }
            else
            {
                var gravity             = (ini["SpellData", "MissileGravity"].Float() ?? 0.0f) * 100.0f;
                var targetHeightAugment = ini["SpellData", "MissileTargetHeightAugment"].Float() ?? 100.0f;
                var speed                          = ini["SpellData", "MissileSpeed"].Float() ?? 500.0f;
                var accel                          = ini["SpellData", "MissileAccel"].Float() ?? 0.0f;
                var maxSpeed                       = ini["SpellData", "MissileMaxSpeed"].Float() ?? speed;
                var minSpeed                       = ini["SpellData", "MissileMinSpeed"].Float() ?? speed;
                var fixedTravelTime                = ini["SpellData", "MissileFixedTravelTime"].Float() ?? 0.0f;
                var minTravelTime                  = ini["SpellData", "MissileMinTravelTime"].Float() ?? 0.0f;
                var lifetime                       = ini["SpellData", "MissileLifetime"].Float() ?? 0.0f;
                var unblockable                    = ini["SpellData", "MissileUnblockable"].Bool() ?? false;
                var blockTriggersOnDestroy         = ini["SpellData", "MissileBlockTriggersOnDestroy"].Bool() ?? true;
                var perceptionBubbleRadius         = ini["SpellData", "MissilePerceptionBubbleRadius"].Float() ?? 0.0f;
                var perceptionBubbleRevealsStealth = ini["SpellData", "MissilePerceptionBubbleRevealsStealth"].Bool() ?? false;
                var updateDistanceInterval         = ini["SpellData", "LuaOnMissileUpdateDistanceInterval"].Float() ?? 0.0f;

                switch (CastType)
                {
                case LeagueSandbox.GameServer.Core.Domain.Enums.CastType.Instant:
                    break;

                case LeagueSandbox.GameServer.Core.Domain.Enums.CastType.Missile:
                    CastData = new CastData.Missile.Normal
                               (
                        gravity: gravity,
                        targetHeightAugment: targetHeightAugment,
                        speed: speed,
                        accel: accel,
                        maxSpeed: maxSpeed,
                        minSpeed: minSpeed,
                        fixedTravelTime: fixedTravelTime,
                        minTravelTime: minTravelTime,
                        lifetime: lifetime,
                        unblockable: unblockable,
                        blockTriggersOnDestroy: blockTriggersOnDestroy,
                        perceptionBubbleRadius: perceptionBubbleRadius,
                        perceptionBubbleRevealsStealth: perceptionBubbleRevealsStealth,
                        updateDistanceInterval: updateDistanceInterval
                               );
                    break;

                case LeagueSandbox.GameServer.Core.Domain.Enums.CastType.ArcMissile:
                    var followsTerrainHeight = ini["SpellData", "LineMissileFollowsTerrainHeight"].Bool() ?? false;
                    var bounces = ini["SpellData", "LineMissileBounces"].Bool() ?? false;
                    var usesAccelerationForBounce = ini["SpellData", "LineMissileUsesAccelerationForBounce"].Bool() ?? false;
                    var trackUnits                         = ini["SpellData", "LineMissileTrackUnits"].Bool() ?? false;
                    var trackUnitsAndContinues             = ini["SpellData", "LineMissileTrackUnitsAndContinues"].Bool() ?? false;
                    var delayDestroyAtEndSeconds           = ini["Spelldata", "LineMissileDelayDestroyAtEndSeconds"].Float() ?? 0.0f;
                    var timePulseBetweenCollisionSpellHits = ini["SpellData", "LineMissileTimePulseBetweenCollisionSpellHits"].Float() ?? 0.0f;
                    var endsAtTargetPoint                  = ini["Spelldata", "LineMissileEndsAtTargetPoint"].Bool() ?? false;
                    CastData = new CastData.Missile.Line
                               (
                        gravity: gravity,
                        targetHeightAugment: targetHeightAugment,
                        speed: speed,
                        accel: accel,
                        maxSpeed: maxSpeed,
                        minSpeed: minSpeed,
                        fixedTravelTime: fixedTravelTime,
                        minTravelTime: minTravelTime,
                        lifetime: lifetime,
                        unblockable: unblockable,
                        blockTriggersOnDestroy: blockTriggersOnDestroy,
                        perceptionBubbleRadius: perceptionBubbleRadius,
                        perceptionBubbleRevealsStealth: perceptionBubbleRevealsStealth,
                        updateDistanceInterval: updateDistanceInterval,
                        followsTerrainHeight: followsTerrainHeight,
                        bounces: bounces,
                        usesAccelerationForBounce: usesAccelerationForBounce,
                        trackUnits: trackUnits,
                        trackUnitsAndContinues: trackUnitsAndContinues,
                        delayDestroyAtEndSeconds: delayDestroyAtEndSeconds,
                        timePulseBetweenCollisionSpellHits: timePulseBetweenCollisionSpellHits,
                        endsAtTargetPoint: endsAtTargetPoint
                               );
                    break;

                case LeagueSandbox.GameServer.Core.Domain.Enums.CastType.ChainMissile:
                    CastData = new CastData.Missile.Chain
                               (
                        gravity: gravity,
                        targetHeightAugment: targetHeightAugment,
                        speed: speed,
                        accel: accel,
                        maxSpeed: maxSpeed,
                        minSpeed: minSpeed,
                        fixedTravelTime: fixedTravelTime,
                        minTravelTime: minTravelTime,
                        lifetime: lifetime,
                        unblockable: unblockable,
                        blockTriggersOnDestroy: blockTriggersOnDestroy,
                        perceptionBubbleRadius: perceptionBubbleRadius,
                        perceptionBubbleRevealsStealth: perceptionBubbleRevealsStealth,
                        updateDistanceInterval: updateDistanceInterval,
                        bounceRadius: ini["SpellData", "BounceRadius"].Float() ?? 450.0f
                               );
                    break;

                case LeagueSandbox.GameServer.Core.Domain.Enums.CastType.CircleMissile:
                    var radialVelocity  = ini["SpellData", "CircleMissileRadialVelocity"].Float() ?? 0.0f;
                    var angularVelocity = ini["SpellData", "CircleMissileAngularVelocity"].Float() ?? 0.0f;
                    CastData = new CastData.Missile.Circle
                               (
                        gravity: gravity,
                        targetHeightAugment: targetHeightAugment,
                        speed: speed,
                        accel: accel,
                        maxSpeed: maxSpeed,
                        minSpeed: minSpeed,
                        fixedTravelTime: fixedTravelTime,
                        minTravelTime: minTravelTime,
                        lifetime: lifetime,
                        unblockable: unblockable,
                        blockTriggersOnDestroy: blockTriggersOnDestroy,
                        perceptionBubbleRadius: perceptionBubbleRadius,
                        perceptionBubbleRevealsStealth: perceptionBubbleRevealsStealth,
                        updateDistanceInterval: updateDistanceInterval,
                        radialVelocity: radialVelocity,
                        angularVelocity: angularVelocity
                               );
                    break;
                }
            }
        }
Beispiel #2
0
        public CharData(string name, IniBin ini)
        {
            var enumTranslationService = new EnumTranslationService();

            Name = name;
            CharDataFlags flags = 0;

            if (ini["Data", "IsEpic"].StringBool() ?? false)
            {
                flags |= CharDataFlags.Epic;
            }
            if (ini["Data", "IsElite"].StringBool() ?? false)
            {
                flags |= CharDataFlags.Elite;
            }
            if (ini["Data", "DrawPARLikeHealth"].StringBool() ?? false)
            {
                flags |= CharDataFlags.DrawPARLikeHealth;
            }
            if (ini["Data", "IsMelee"].StringBool() ?? false)
            {
                flags |= CharDataFlags.Melee;
            }
            if (ini["Data", "NeverRender"].Bool() ?? false)
            {
                flags |= CharDataFlags.NeverRender;
            }
            if (ini["Data", "ServerOnly"].Bool() ?? false)
            {
                flags |= CharDataFlags.ServerOnly;
            }
            if (ini["Data", "NoAutoAttack"].Bool() ?? false)
            {
                flags |= CharDataFlags.NoAutoAttack;
            }
            if (ini["Data", "NoHealthBar"].Bool() ?? false)
            {
                flags |= CharDataFlags.NoHealthBar;
            }
            if (ini["Data", "ShouldFaceTarget"].Bool() ?? true)
            {
                flags |= CharDataFlags.ShouldFaceTarget;
            }
            if (ini["Data", "PARDisplayThroughDeath"].Bool() ?? false)
            {
                flags |= CharDataFlags.PARDisplayThroughDeath;
            }
            if (ini["Data", "AllowPetControl"].Bool() ?? true)
            {
                flags |= CharDataFlags.AllowPetControl;
            }
            if (ini["Data", "SkipDrawOutline"].Bool() ?? false)
            {
                flags |= CharDataFlags.SkipDrawOutline;
            }
            if (ini["Data", "UseChampionVisibility"].Bool() ?? false)
            {
                flags |= CharDataFlags.UseChampionVisibility;
            }
            if (ini["Data", "TriggersOrderAcknowledgementVO"].StringBool() ?? true)
            {
                flags |= CharDataFlags.TriggersOrderAcknowledgementVO;
            }
            if (ini["Data", "FireworksEnabled"].Bool() ?? false)
            {
                flags |= CharDataFlags.HasExpandedVO;
            }
            if (ini["Data", "DisableUltReadySounds"].Bool() ?? false)
            {
                flags |= CharDataFlags.DisableUltReadySounds;
            }
            if (ini["Data", "IsImportantBotTarget"].Bool() ?? false)
            {
                flags |= CharDataFlags.IsImportantBotTarget;
            }
            if (ini["Data", "DisableGlobalDeathEffect"].Bool() ?? false)
            {
                flags |= CharDataFlags.DisableGlobalDeathEffect;
            }
            if (ini["Data", "DisableAggroIndicator"].Bool() ?? false)
            {
                flags |= CharDataFlags.DisableAggroIndicator;
            }
            if (ini["Data", "SequentialAutoAttacks"].Bool() ?? false)
            {
                flags |= CharDataFlags.SequentialAutoAttacks;
            }
            if (ini["Data", "DisableContinuousTargetFacing"].Bool() ?? false)
            {
                flags |= CharDataFlags.DisableContinuousTargetFacing;
            }
            if (ini["Data", "Immobile"].Bool() ?? false)
            {
                flags |= CharDataFlags.Immobile;
            }
            if (ini["Data", "UseRingIconForKillCallout"].Bool() ?? true)
            {
                flags |= CharDataFlags.UseRingIconForKillCallout;
            }
            Flags                          = flags;
            PARType                        = enumTranslationService.TranslatePrimaryAbilityResourceType(ini["Data", "PARType"].StringEnum <PARType>() ?? LeagueData.PARType.Mana);
            AssetCategory                  = ini["Data", "AssetCategory"].String() ?? "character";
            MonsterDataTableID             = ini["Data", "MonsterDataTableID"].Int() ?? 0;
            RecordAsWard                   = ini["Data", "RecordAsWard"].Bool() ?? false;
            PostAttackMoveDelay            = ini["Data", "PostAttackMoveDelay"].Float() ?? 0.0f;
            ChasingAttackRangePercent      = ini["Data", "ChasingAttackRangePercent"].Float() ?? 0.5f;
            ChampionId                     = ini["Data", "ChampionId"].Int() ?? 0;
            BaseSpellEffectiveness         = ini["Data", "BaseSpellEffectiveness"].Float() ?? 0.0f;
            BaseHP                         = ini["Data", "BaseHP"].Float() ?? 100.0f;
            BasePAR                        = ini["Data", "BaseMP"].Float() ?? 100.0f;
            HPPerLevel                     = ini["Data", "HPPerLevel"].Float() ?? 0.0f;
            PARPerLevel                    = ini["Data", "MPPerLevel"].Float() ?? 0.0f;
            HPRegenPerLevel                = ini["Data", "HPRegenPerLevel"].Float() ?? 0.0f;
            PARRegenPerLevel               = ini["Data", "MPRegenPerLevel"].Float() ?? 0.0f;
            BaseStaticHPRegen              = ini["Data", "BaseStaticHPRegen"].Float() ?? 1.0f;
            BaseFactorHPRegen              = ini["Data", "BaseFactorHPRegen"].Float() ?? 0.0f;
            BaseStaticPARRegen             = ini["Data", "BaseStaticMPRegen"].Float() ?? 1.0f;
            BaseFactorPARRegen             = ini["Data", "BaseFactorMPRegen"].Float() ?? 0.0f;
            BasePhysicalDamage             = ini["Data", "BaseDamage"].Float() ?? 10.0f;
            PhysicalDamagePerLevel         = ini["Data", "DamagePerLevel"].Float() ?? 0.0f;
            BaseAbilityPower               = ini["Data", "BaseAbilityPower"].Float() ?? 0.0f;
            AbilityPowerIncPerLevel        = ini["Data", "AbilityPowerIncPerLevel"].Float() ?? 0.0f;
            BaseArmor                      = ini["Data", "Armor"].Float() ?? 1.0f;
            ArmorPerLevel                  = ini["Data", "ArmorPerLevel"].Float() ?? 0.0f;
            BaseSpellBlock                 = ini["Data", "SpellBlock"].Float() ?? 0.0f;
            SpellBlockPerLevel             = ini["Data", "SpellBlockPerLevel"].Float() ?? 0.0f;
            BaseDodge                      = ini["Data", "BaseDodge"].Float() ?? 0.0f;
            DodgePerLevel                  = ini["Data", "LevelDodge"].Float() ?? 0.0f;
            BaseMissChance                 = ini["Data", "BaseMissChance"].Float() ?? 0.0f;
            BaseCritChance                 = ini["Data", "BaseCritChance"].Float() ?? 0.0f;
            CritChancePerLevel             = ini["Data", "CritPerLevel"].Float() ?? 0.0f;
            CritDamageMultiplier           = ini["Data", "CritDamageBonus"].Float() ?? 2.0f;
            BaseMoveSpeed                  = ini["Data", "MoveSpeed"].Float() ?? 100.0f;
            AttackRange                    = ini["Data", "AttackRange"].Float() ?? 100.0f;
            AttackAutoInterruptPercent     = ini["Data", "AttackAutoInterruptPercent"].Float() ?? 0.2f;
            AcquisitionRange               = ini["Data", "AcquisitionRange"].Float() ?? 750.0f;
            AttackSpeedPerLevel            = (ini["Data", "AttackSpeedPerLevel"].Float() ?? 0.0f) / 100.0f;
            TowerTargetingPriority         = ini["Data", "TowerTargetingPriorityBoost"].Float() ?? 0.0f;
            DeathTime                      = ini["Data", "DeathTime"].Float() ?? -1.0f;
            ExpGivenOnDeath                = ini["Data", "ExpGivenOnDeath"].Float() ?? 48.0f;
            GoldGivenOnDeath               = ini["Data", "GoldGivenOnDeath"].Float() ?? 25.0f;
            GoldRadius                     = ini["Data", "GoldRadius"].Float() ?? 0.0f;
            ExperienceRadius               = ini["Data", "ExperienceRadius"].Float() ?? 0.0f;
            DeathEventListeningRadius      = ini["Data", "DeathEventListeningRadius"].Float() ?? 1000.0f;
            LocalGoldSplitWithLastHitter   = ini["Data", "LocalGoldSplitWithLastHitter"].Bool() ?? false;
            LocalGoldGivenOnDeath          = ini["Data", "LocalGoldGivenOnDeath"].Float() ?? 0.0f;
            LocalExpGivenOnDeath           = ini["Data", "LocalExpGivenOnDeath"].Float() ?? 0.0f;
            GlobalGoldGivenOnDeath         = ini["Data", "GlobalGoldGivenOnDeath"].Float() ?? 0.0f;
            GlobalExpGivenOnDeath          = ini["Data", "GlobalExpGivenOnDeath"].Float() ?? 0.0f;
            Significance                   = ini["Data", "Significance"].Float() ?? 0.0f;
            PerceptionBubbleRadius         = ini["Data", "PerceptionBubbleRadius"].Float() ?? 1350.0f;
            HitFxScale                     = ini["Data", "HitFxScale"].Float() ?? 1.0f;
            OverrideCollisionHeight        = ini["Data", "SelectionHeight"].Float() ?? -1.0f;
            OverrideCollisionRadius        = ini["Data", "SelectionRadius"].Float() ?? -1.0f;
            PathfindingCollisionRadius     = ini["Data", "PathfindingCollisionRadius"].Float() ?? -1.0f;
            GameplayCollisionRadius        = ini["Data", "GameplayCollisionRadius"].Float() ?? 65.0f;
            OccludedUnitSelectableDistance = ini["Data", "OccludedUnitSelectableDistance"].Float() ?? 0.0f;

            PassiveData = new PassiveData(
                luaName: ini["Data", "Passive1LuaNam"].String() ?? "",
                range: ini["Data", "Passive1Range"].Float() ?? 0.0f
                );

            var maxLevels = ini["Data", "MaxLevels"].IntList(5, 5, 5, 3);

            Spells = new Dictionary <SpellSlot, IBaseSpellData>
            {
                { SpellSlot.Q, new BaseSpellData
                  (
                      name: ini["Data", "Spell1"].String() ?? "",
                      maxLevelOverride: maxLevels[0],
                      upgradeLevels: ini["Data", $"SpellsUpLevels1"].IntList(1, 3, 5, 7, 9, 99)
                  ) },
                { SpellSlot.W, new BaseSpellData
                  (
                      name: ini["Data", "Spell2"].String() ?? "",
                      maxLevelOverride: maxLevels[1],
                      upgradeLevels: ini["Data", $"SpellsUpLevels2"].IntList(1, 3, 5, 7, 9, 99)
                  ) },
                { SpellSlot.E, new BaseSpellData
                  (
                      name: ini["Data", "Spell3"].String() ?? "",
                      maxLevelOverride: maxLevels[2],
                      upgradeLevels: ini["Data", $"SpellsUpLevels3"].IntList(1, 3, 5, 7, 9, 99)
                  ) },
                { SpellSlot.R, new BaseSpellData
                  (
                      name: ini["Data", "Spell4"].String() ?? "",
                      maxLevelOverride: maxLevels[3],
                      upgradeLevels: ini["Data", $"SpellsUpLevels4"].IntList(6, 11, 16, 99, 99, 99)
                  ) },
            };

            ExtraSpells    = Enumerable.Range(1, 16).Select((i) => new KeyValuePair <SpellSlot, string>((SpellSlot)Math.Pow(2, 5 + i), ini["Data", $"ExtraSpell{i}"].String() ?? "")).ToDictionary(x => x.Key, x => x.Value);
            CriticalAttack = ini["Data", "CriticalAttack"].String() ?? "";


            var        attacksData = new Dictionary <SpellSlot, IAttackData>(18);
            AttackData baseAttack;

            {
                var attackName        = ini["Data", $"{_attackNames[0]}"].String() ?? $"{name}{_attackDefaults[0]}";
                var attackProbability = ini["Data", $"{_attackNames[0]}_Probability"].Float() ?? 2.0f;
                var attackCastTime    = ini["Data", "AttackCastTime"].Float() ?? 0.0f;
                var attackTotalTime   = ini["Data", "AttackTotalTime"].Float() ?? 0.0f;
                if (attackCastTime > 0.0f && attackTotalTime > 0.0f)
                {
                    baseAttack = new AttackData
                                 (
                        name: attackName,
                        probability: attackProbability,
                        totalTime: attackTotalTime,
                        castTime: attackCastTime
                                 );
                }
                else
                {
                    var delayOffsetPercent     = ini["Data", $"AttackDelayOffsetPercent"].Float() ?? 0.0f;
                    var delayCastOffsetPercent = ini["Data", $"AttackDelayCastOffsetPercent"].Float() ?? 0.0f;
                    var delayCastOffsetPercentAttackSpeedRatio = ini["Data", $"AttackDelayCastOffsetPercentAttackSpeedRatio"].Float() ?? 1.0f;
                    baseAttack = new AttackData
                                 (
                        name: attackName,
                        probability: attackProbability,
                        delayOffsetPercent: delayOffsetPercent,
                        delayCastOffsetPercent: delayCastOffsetPercent,
                        delayCastOffsetPercentAttackSpeedRatio: delayCastOffsetPercentAttackSpeedRatio
                                 );
                }
            }
            attacksData.Add(SpellSlot.BaseAttack, baseAttack);
            for (int i = 1; i < 18; i++)
            {
                AttackData attack;
                var        attackName        = ini["Data", $"{_attackNames[i]}"].String() ?? $"{name}{_attackDefaults[i]}";
                var        attackProbability = ini["Data", $"{_attackNames[i]}_Probability"].Float() ?? 2.0f;
                var        attackCastTime    = ini["Data", $"{_attackNames[i]}_AttackCastTime"].Float() ?? 0.0f;
                var        attackTotalTime   = ini["Data", $"{_attackNames[i]}_AttackTotalTime"].Float() ?? 0.0f;
                if (attackCastTime > 0.0f && attackTotalTime > 0.0f)
                {
                    attack = new AttackData
                             (
                        name: attackName,
                        probability: attackProbability,
                        totalTime: attackTotalTime,
                        castTime: attackCastTime
                             );
                }
                else
                {
                    var delayOffsetPercent     = ini["Data", $"{_attackNames[i]}_AttackDelayOffsetPercent"].Float() ?? baseAttack.DelayOffsetPercent;
                    var delayCastOffsetPercent = ini["Data", $"{_attackNames[i]}_AttackDelayCastOffsetPercent"].Float() ?? baseAttack.DelayCastOffsetPercent;
                    var delayCastOffsetPercentAttackSpeedRatio = ini["Data", $"{_attackNames[i]}_AttackDelayCastOffsetPercentAttackSpeedRatio"].Float() ?? baseAttack.DelayCastOffsetPercentAttackSpeedRatio;
                    attack = new AttackData
                             (
                        name: attackName,
                        probability: attackProbability,
                        delayOffsetPercent: delayOffsetPercent,
                        delayCastOffsetPercent: delayCastOffsetPercent,
                        delayCastOffsetPercentAttackSpeedRatio: delayCastOffsetPercentAttackSpeedRatio
                             );
                }
                attacksData.Add((SpellSlot)(1L << (22 + i)), attack);
            }
            AttacksData = attacksData;
        }