Files

156 lines
7.6 KiB
C#

using System;
using BumpCombat.Core;
using BumpCombat.Enemies;
using UnityEngine;
namespace BumpCombat.Constants
{
[Serializable]
public struct SpawnDensityPhase
{
[Tooltip("다음 단계로 넘어가는 진행시간 (초). 마지막 단계는 무시됩니다.")]
public float EndTimeSeconds;
[Min(0)] public int CrowdTarget;
[Min(0)] public int NormalTarget;
public SpawnDensityPhase(float endTimeSeconds, int crowdTarget, int normalTarget)
{
EndTimeSeconds = endTimeSeconds;
CrowdTarget = crowdTarget;
NormalTarget = normalTarget;
}
}
[CreateAssetMenu(menuName = "BumpCombat/Constants/Run and Spawning")]
public sealed class RunConstants : ScriptableObject
{
[Header("런 이벤트 시간표 (초)")]
public float[] DevelopmentEliteEventTimes = { 36f, 72f, 108f, 144f, 180f, 216f };
public float[] FormalEliteEventTimes = { 180f, 360f, 540f, 720f, 900f, 1080f };
public float[] ProductionEliteEventTimes = { 180f, 360f, 540f, 720f };
[Min(0f)] public float DevelopmentProgressionMultiplier = 5f;
[Min(0f)] public float DevelopmentMidBossEventTime = 120f;
[Min(0f)] public float DevelopmentFinalBossEventTime = 240f;
[Min(0f)] public float FormalMidBossEventTime = 600f;
[Min(0f)] public float FormalFinalBossEventTime = 1200f;
[Min(0f)] public float ProductionMidBossEventTime = 600f;
[Min(0f)] public float ProductionFinalBossEventTime = 900f;
[Min(0)] public int DevelopmentStartupArtifactSelectionCount = 3;
[Min(0)] public int ProductionStartupArtifactSelectionCount = 1;
[Min(0)] public int LegacyStartupArtifactSelectionCount = 3;
[Header("스폰 밀도 단계")]
[Tooltip("순서대로 시작시점, 1분, 3분, 5분, 10분 이후의 군중형/일반형 목표 수")]
public SpawnDensityPhase[] SpawnDensity =
{
new(60f, 3, 3), new(180f, 6, 4), new(300f, 12, 4),
new(600f, 19, 5), new(float.PositiveInfinity, 27, 5),
};
[Min(0)] public int TimedEventCrowdTarget = 5;
[Min(0)] public int TimedEventNormalTarget = 3;
[Min(0)] public int FinalBossMaximumCrowdTarget = 2;
[Header("웨이브")]
[Min(1)] public int MaximumAliveEnemies = 100;
[Min(1)] public int MaximumBossEncounterEnemies = 8;
[Min(0.1f)] public float WaveInterval = 5f;
[Min(0.1f)] public float TimedEventWaveInterval = 12f;
[Min(1)] public int MaximumWaveSize = 3;
[Min(1)] public int MaximumTimedEventWaveSize = 1;
[Min(0f)] public float InitialWaveDelay = 0.5f;
[Header("실제 플레이 유입량·습격")]
[Min(0)] public int ProductionWaveCrowdSize = 2;
[Min(0)] public int ProductionWaveNormalSize = 1;
[Min(0)] public int ProductionTimedEventCrowdSize = 1;
[Min(0f)] public float ProductionSwarmInterval = 90f;
[Min(0f)] public float ProductionSwarmBossExclusionWindow = 30f;
[Min(0f)] public float ProductionSwarmEarlyEndTime = 300f;
[Min(0f)] public float ProductionSwarmMidEndTime = 600f;
[Min(0)] public int ProductionSwarmEarlyCount = 16;
[Min(0)] public int ProductionSwarmMidCount = 20;
[Min(0)] public int ProductionSwarmLateCount = 24;
[Min(1)] public int ProductionSwarmBatchSize = 4;
[Min(0.1f)] public float ProductionSwarmBatchInterval = 2f;
[Header("스폰 위치")]
[Min(0f)] public float SpawnEdgeInset = 0.25f;
[Min(0f)] public float PlayerSafeSpawnDistance = 4f;
[Min(0f)] public float SpawnCameraMargin = 0.5f;
[Min(0f)] public float SummonSpawnRadius = 2.5f;
[Min(0f)] public float SummonSpawnMinimumSeparation = 1.5f;
[Min(0f)] public float SummonSpawnPlayerClearance = 1.25f;
public Vector2 FallbackSpawnHalfExtents = new(14.5f, 7.8125f);
[Tooltip("시간 중간보스의 후보 프리팹 종류")]
public EnemyKind[] MidBossKinds = { EnemyKind.GreatswordSkeleton, EnemyKind.NecroGolem };
[Header("이벤트 적 기본 튜닝")]
public RunEventEnemyTuning EliteTuning = RunEventEnemyTuning.Create(
EnemyKind.Lancer, 3f, 30, 1.25f, Color.white, 1.05f, 1.1f, 0.85f, 1f,
0.7f, 1f, 1.1f, 1.15f, 1f, 2, 0.7f, 0.35f, 2, 0.65f, true);
public RunEventEnemyTuning MidBossTuning = RunEventEnemyTuning.Create(
EnemyKind.GreatswordSkeleton, 8f, 100, 1.6f, new Color(1f, 0.35f, 0.3f),
0.9f, 1.25f, 0.95f, 1f, 0.8f, 1.15f, 1f, 1f, 1.35f, 2, 0.7f,
0.4f, 3, 0.3f, false);
public RunEventEnemyTuning FinalBossTuning = RunEventEnemyTuning.Create(
EnemyKind.Warlock, 15f, 0, 2f, new Color(0.75f, 0.35f, 1f), 0.85f,
1.25f, 0.9f, 1f, 0.75f, 1f, 1f, 1f, 1.25f, 3, 0.75f, 0.3f,
4, 0.15f, false);
[Min(1f)] public float ProductionMidBossHealthMultiplier = 7f;
[Min(1f)] public float ProductionFinalBossHealthMultiplier = 12f;
[Tooltip("순서대로 첫 번째, 두 번째, 세 번째, 이후 시간 엘리트 체력 배율")]
public float[] ProductionEliteHealthMultipliers = { 2.5f, 3.5f, 3.5f, 5f };
[Tooltip("순서대로 첫 번째, 두 번째, 세 번째, 이후 시간 엘리트 공격 배율")]
public float[] ProductionEliteAttackDamageMultipliers = { 1f, 1f, 1.1f, 1.2f };
[Tooltip("순서대로 첫 번째, 두 번째, 세 번째, 이후 시간 엘리트 연속 공격 수")]
public int[] ProductionEliteAttacksPerSequence = { 1, 2, 3, 2 };
[Tooltip("엘리트 순환에 사용할 적 종류")]
public EnemyKind[] EliteKinds =
{
EnemyKind.ArmoredSkeleton,
EnemyKind.Werewolf,
EnemyKind.Werebear,
};
[Tooltip("개발 런에서 순서대로 적용할 엘리트 연속 공격 수")]
public int[] DevelopmentEliteAttacksPerSequence = { 2, 2, 3 };
[Tooltip("생산 런에서 순서대로 적용할 엘리트 경고시간 배율")]
public float[] ProductionEliteWarningDurationMultipliers = { 1f, 0.85f, 0.85f, 0.85f };
[Tooltip("생산 런에서 순서대로 적용할 엘리트 회복시간 배율")]
public float[] ProductionEliteRecoveryDurationMultipliers = { 1f, 0.7f, 0.7f, 0.7f };
[Header("전장")]
public Vector2 ArenaBackgroundHalfExtents = new(15f, 8.4375f);
public Vector2 ArenaPlayableHalfExtents = new(15f, 8.4375f);
public Vector2 ArenaPlayerPadding = new(0.5f, 0.625f);
public Vector2 ArenaCameraViewHalfExtents = new(10f, 5.625f);
public Vector2 ArenaCameraDeadZone = new(0.5f, 0.3f);
[Min(0f)] public float ArenaCameraSmoothTime = 0.15f;
public float[] EliteTimes(bool development, bool production)
{
float[] times = production
? ProductionEliteEventTimes
: development ? DevelopmentEliteEventTimes : FormalEliteEventTimes;
return times ?? Array.Empty<float>();
}
public SpawnDensityPhase GetSpawnDensity(float elapsedTime)
{
if (SpawnDensity == null || SpawnDensity.Length == 0)
{
return new SpawnDensityPhase(float.PositiveInfinity, 27, 5);
}
for (int i = 0; i < SpawnDensity.Length - 1; i++)
{
if (elapsedTime < SpawnDensity[i].EndTimeSeconds)
{
return SpawnDensity[i];
}
}
return SpawnDensity[SpawnDensity.Length - 1];
}
}
}