Files

313 lines
18 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
// ВСЕ ИГРОВЫЕ ТАБЛИЦЫ В ОДНОМ МЕСТЕ: задания, войска, награды, магазин, событие.
// Баланс правится здесь -- числа, названия, награды. Логика лежит в GameProgress и панелях.
[Serializable]
public class RewardItem
{
public ResourceType type;
public int amount;
public RewardItem() { }
public RewardItem(ResourceType type, int amount) { this.type = type; this.amount = amount; }
}
public enum QuestKind
{
TownHallLevel, // улучшить Ратушу до уровня N
BuildingsBuilt, // построить N зданий
Collect, // собрать N ресурса
BattlesWon, // выиграть N боёв
TroopsTrained, // обучить N воинов
HeroLevel, // герой N уровня
ArenaFights, // N боёв на арене
PlayerLevel, // уровень игрока N
Login, // зайти в игру (ежедневное)
WorldMarches, // отправить N походов на глобальной карте
WorldWins, // победить N раз на глобальной карте
BarracksBuilt // построить N казарм
}
public class QuestDef
{
public string id;
public string title;
public QuestKind kind;
public ResourceType resource;
public int target;
public int xp;
public RewardItem[] rewards;
public QuestDef(string id, string title, QuestKind kind, int target, int xp, params RewardItem[] rewards)
{
this.id = id; this.title = title; this.kind = kind; this.target = target; this.xp = xp; this.rewards = rewards;
}
public QuestDef Res(ResourceType r) { resource = r; return this; }
}
public class TroopDef
{
public string name;
public string description;
public int power; // сила одного воина
public float secondsPerUnit; // время обучения одного
public int requiredTownHall;
public RewardItem[] cost; // цена одного воина
public Color color;
public TroopDef(string name, string description, int power, float seconds, int th, Color color, params RewardItem[] cost)
{
this.name = name; this.description = description; this.power = power; secondsPerUnit = seconds;
requiredTownHall = th; this.color = color; this.cost = cost;
}
}
public class ShopItemDef
{
public string id;
public string title;
public RewardItem[] gives;
public ResourceType priceType;
public int price; // 0 = бесплатно
public int dailyLimit; // 0 = без лимита
public bool comingSoon; // покупка за реальные деньги -- пока недоступна
public string priceLabel;
public ShopItemDef(string id, string title, ResourceType priceType, int price, int dailyLimit, params RewardItem[] gives)
{
this.id = id; this.title = title; this.priceType = priceType; this.price = price; this.dailyLimit = dailyLimit; this.gives = gives;
}
}
public static class GameData
{
// ---------- Названия ресурсов на русском ----------
public static string ResName(ResourceType t)
{
switch (t)
{
case ResourceType.Population: return "Люди";
case ResourceType.Food: return "Еда";
case ResourceType.Wood: return "Дерево";
case ResourceType.Stone: return "Камень";
case ResourceType.Iron: return "Железо";
case ResourceType.Gold: return "Золото";
case ResourceType.Gems: return "Кристаллы";
case ResourceType.Power: return "Сила";
}
return t.ToString();
}
public static Color ResColor(ResourceType t)
{
switch (t)
{
case ResourceType.Food: return new Color(0.85f, 0.45f, 0.3f);
case ResourceType.Wood: return new Color(0.6f, 0.4f, 0.2f);
case ResourceType.Stone: return new Color(0.6f, 0.6f, 0.65f);
case ResourceType.Iron: return new Color(0.45f, 0.55f, 0.7f);
case ResourceType.Gold: return new Color(1f, 0.8f, 0.2f);
case ResourceType.Gems: return new Color(0.4f, 0.85f, 1f);
case ResourceType.Power: return new Color(1f, 0.4f, 0.3f);
}
return new Color(0.8f, 0.8f, 0.8f);
}
static RewardItem R(ResourceType t, int a) { return new RewardItem(t, a); }
// ---------- Опыт игрока ----------
public static int XpToNextLevel(int level) { return 100 + (level - 1) * 80; }
public const int MaxPlayerLevel = 60;
// ---------- Основные задания (цепочка) ----------
public static readonly List<QuestDef> MainQuests = new List<QuestDef>
{
new QuestDef("m_collect_wood_1", "Собрать 200 дерева", QuestKind.Collect, 200, 30, R(ResourceType.Gold, 200)).Res(ResourceType.Wood),
new QuestDef("m_collect_food_1", "Собрать 200 еды", QuestKind.Collect, 200, 30, R(ResourceType.Gold, 200)).Res(ResourceType.Food),
new QuestDef("m_build_1", "Построить первое здание", QuestKind.BuildingsBuilt, 1, 50, R(ResourceType.Wood, 300), R(ResourceType.Stone, 200)),
new QuestDef("m_barracks", "Построить Казармы", QuestKind.BarracksBuilt, 1, 50, R(ResourceType.Food, 300), R(ResourceType.Wood, 200)),
new QuestDef("m_train_10", "Обучить 10 воинов", QuestKind.TroopsTrained, 10, 50, R(ResourceType.Food, 400)),
new QuestDef("m_battle_1", "Выиграть первый бой", QuestKind.BattlesWon, 1, 60, R(ResourceType.Gems, 30)),
new QuestDef("m_world_send", "Отправить армию в поход на карте мира", QuestKind.WorldMarches, 1, 60, R(ResourceType.Food, 500)),
new QuestDef("m_world_win", "Разграбить поселение на карте мира", QuestKind.WorldWins, 1, 100, R(ResourceType.Gems, 50), R(ResourceType.Gold, 500)),
new QuestDef("m_hero_3", "Герой 3 уровня", QuestKind.HeroLevel, 3, 60, R(ResourceType.Gold, 500)),
new QuestDef("m_th_2", "Ратуша 2 уровня", QuestKind.TownHallLevel, 2, 100, R(ResourceType.Gems, 50), R(ResourceType.Stone, 500)),
new QuestDef("m_build_3", "Построить 3 здания", QuestKind.BuildingsBuilt, 3, 80, R(ResourceType.Wood, 600), R(ResourceType.Iron, 200)),
new QuestDef("m_arena_1", "Сразиться на арене", QuestKind.ArenaFights, 1, 60, R(ResourceType.Gems, 20)),
new QuestDef("m_collect_stone_1", "Собрать 1000 камня", QuestKind.Collect, 1000, 80, R(ResourceType.Gold, 800)).Res(ResourceType.Stone),
new QuestDef("m_train_100", "Обучить 100 воинов", QuestKind.TroopsTrained, 100, 120, R(ResourceType.Food, 1500), R(ResourceType.Gems, 30)),
new QuestDef("m_battle_5", "Выиграть 5 боёв", QuestKind.BattlesWon, 5, 150, R(ResourceType.Gems, 60)),
new QuestDef("m_player_5", "Достигнуть 5 уровня", QuestKind.PlayerLevel, 5, 100, R(ResourceType.Gems, 100)),
new QuestDef("m_th_3", "Ратуша 3 уровня", QuestKind.TownHallLevel, 3, 200, R(ResourceType.Gems, 100), R(ResourceType.Iron, 800)),
new QuestDef("m_hero_10", "Герой 10 уровня", QuestKind.HeroLevel, 10, 200, R(ResourceType.Gold, 3000)),
new QuestDef("m_battle_15", "Выиграть 15 боёв", QuestKind.BattlesWon, 15, 300, R(ResourceType.Gems, 150)),
new QuestDef("m_th_5", "Ратуша 5 уровня", QuestKind.TownHallLevel, 5, 400, R(ResourceType.Gems, 250)),
};
// ---------- Ежедневные задания (сбрасываются каждый день) ----------
public static readonly List<QuestDef> DailyQuests = new List<QuestDef>
{
new QuestDef("d_login", "Зайти в игру", QuestKind.Login, 1, 10, R(ResourceType.Gold, 100)),
new QuestDef("d_wood", "Собрать 300 дерева", QuestKind.Collect, 300, 20, R(ResourceType.Food, 200)).Res(ResourceType.Wood),
new QuestDef("d_food", "Собрать 300 еды", QuestKind.Collect, 300, 20, R(ResourceType.Wood, 200)).Res(ResourceType.Food),
new QuestDef("d_train", "Обучить 20 воинов", QuestKind.TroopsTrained, 20, 25, R(ResourceType.Iron, 150)),
new QuestDef("d_battle", "Выиграть 1 бой", QuestKind.BattlesWon, 1, 30, R(ResourceType.Gems, 10)),
new QuestDef("d_arena", "2 боя на арене", QuestKind.ArenaFights, 2, 30, R(ResourceType.Gems, 10)),
new QuestDef("d_world", "Отправить поход на карте мира", QuestKind.WorldMarches, 1, 25, R(ResourceType.Gold, 200)),
};
// ---------- Войска ----------
public static readonly List<TroopDef> Troops = new List<TroopDef>
{
new TroopDef("Пехота", "Дешёвые и надёжные бойцы ближнего боя.", 4, 3f, 1, new Color(0.55f, 0.6f, 0.7f),
R(ResourceType.Food, 20), R(ResourceType.Wood, 10)),
new TroopDef("Лучники", "Бьют издалека, хороши против пехоты.", 5, 4f, 1, new Color(0.45f, 0.7f, 0.4f),
R(ResourceType.Food, 15), R(ResourceType.Wood, 25)),
new TroopDef("Кавалерия", "Быстрые и сильные всадники.", 9, 7f, 2, new Color(0.75f, 0.55f, 0.3f),
R(ResourceType.Food, 40), R(ResourceType.Iron, 15)),
new TroopDef("Осадные", "Катапульты: огромная сила, долгая сборка.", 16, 12f, 3, new Color(0.7f, 0.35f, 0.35f),
R(ResourceType.Wood, 60), R(ResourceType.Stone, 40), R(ResourceType.Iron, 30)),
};
// Размер очереди обучения зависит от числа казарм: см. Barracks.QueueSize
// ---------- Герой ----------
public static int HeroMaxLevel(int townHallLevel) { return Mathf.Min(50, Mathf.Max(1, townHallLevel) * 5); }
public static int HeroAttack(int lvl) { return 10 + (lvl - 1) * 5; }
public static int HeroDefense(int lvl) { return 8 + (lvl - 1) * 4; }
public static int HeroArmyBonusPercent(int lvl) { return lvl * 2; }
public static int HeroPower(int lvl) { return 60 + lvl * 40; }
public static RewardItem[] HeroUpgradeCost(int lvl)
{
float m = Mathf.Pow(1.35f, lvl - 1);
return new[] { R(ResourceType.Gold, Mathf.RoundToInt(100 * m)), R(ResourceType.Food, Mathf.RoundToInt(150 * m)) };
}
public static readonly int[] HeroSkillLevels = { 1, 5, 10, 20, 35 };
public static readonly string[] HeroSkillNames =
{
"Боевой клич: +5% к силе армии",
"Железная стена: +10% защиты войск",
"Вдохновение: +10% к наградам за бой",
"Стратег: потери в бою -20%",
"Легенда: +15% к силе армии",
};
// ---------- Кампания (вкладка "Бой") ----------
public static readonly string[] EnemyNames =
{
"Лагерь разбойников", "Волчье логово", "Застава мародёров", "Гоблинский форт", "Тёмная роща",
"Пиратская бухта", "Крепость орков", "Проклятые руины", "Логово тролля", "Цитадель некроманта"
};
public static string StageName(int stage) { return EnemyNames[(stage - 1) % EnemyNames.Length] + (stage > EnemyNames.Length ? " II" : ""); }
public static int StageEnemyPower(int stage) { return Mathf.RoundToInt(80f * Mathf.Pow(1.22f, stage - 1)); }
public static RewardItem[] StageRewards(int stage)
{
return new[]
{
R(ResourceType.Gold, 60 + stage * 25),
R(ResourceType.Food, 80 + stage * 30),
R(ResourceType.Iron, 20 + stage * 10),
};
}
public static int StageXp(int stage) { return 20 + stage * 6; }
public static int StageGems(int stage) { return stage % 5 == 0 ? 25 : 0; } // каждый 5-й этап -- кристаллы
// ---------- Арена ----------
public const int ArenaMaxTickets = 5;
public const int ArenaTicketMinutes = 20;
public static readonly string[] BotNames =
{
"Ярослав", "Мирон", "Север", "Ведана", "Ратибор", "Злата", "Горыня", "Любава", "Святогор", "Огнеслав",
"Ingvar", "Sigrun", "Bjorn", "Astrid", "Leif", "Ragnar", "Freya", "Ulf", "Helga", "Torvald"
};
public static string ArenaLeague(int rating)
{
if (rating < 1100) return "Бронза";
if (rating < 1300) return "Серебро";
if (rating < 1600) return "Золото";
if (rating < 2000) return "Платина";
return "Алмаз";
}
// ---------- Ежедневная награда за вход (7 дней) ----------
public static readonly RewardItem[][] LoginRewards =
{
new[] { R(ResourceType.Gold, 500) },
new[] { R(ResourceType.Food, 1000) },
new[] { R(ResourceType.Wood, 800), R(ResourceType.Stone, 500) },
new[] { R(ResourceType.Gems, 50) },
new[] { R(ResourceType.Iron, 600) },
new[] { R(ResourceType.Gold, 2000) },
new[] { R(ResourceType.Gems, 200) },
};
// ---------- Магазин ----------
public static readonly List<ShopItemDef> ShopItems = BuildShop();
static List<ShopItemDef> BuildShop()
{
var list = new List<ShopItemDef>
{
new ShopItemDef("free_chest", "Бесплатный сундук (раз в день)", ResourceType.Gems, 0, 1),
new ShopItemDef("wood_1k", "Пакет дерева", ResourceType.Gems, 50, 5, R(ResourceType.Wood, 1000)),
new ShopItemDef("stone_1k", "Пакет камня", ResourceType.Gems, 50, 5, R(ResourceType.Stone, 1000)),
new ShopItemDef("food_15", "Пакет еды", ResourceType.Gems, 50, 5, R(ResourceType.Food, 1500)),
new ShopItemDef("iron_500", "Пакет железа", ResourceType.Gems, 60, 5, R(ResourceType.Iron, 500)),
new ShopItemDef("gold_1k", "Мешок золота", ResourceType.Gems, 80, 3, R(ResourceType.Gold, 1000)),
new ShopItemDef("gems_10", "Обмен золота на кристаллы", ResourceType.Gold, 1000, 3, R(ResourceType.Gems, 10)),
};
var p1 = new ShopItemDef("iap_small", "Горсть кристаллов", ResourceType.Gems, 0, 0, R(ResourceType.Gems, 500));
p1.comingSoon = true; p1.priceLabel = "99 руб.";
var p2 = new ShopItemDef("iap_big", "Сундук кристаллов", ResourceType.Gems, 0, 0, R(ResourceType.Gems, 3000));
p2.comingSoon = true; p2.priceLabel = "499 руб.";
list.Add(p1); list.Add(p2);
return list;
}
// Содержимое бесплатного сундука (выбирается случайно)
public static readonly RewardItem[] FreeChestPool =
{
R(ResourceType.Wood, 500), R(ResourceType.Stone, 400), R(ResourceType.Food, 600),
R(ResourceType.Iron, 250), R(ResourceType.Gold, 400), R(ResourceType.Gems, 15),
};
// ---------- Еженедельное событие ----------
public const string EventTitle = "Сбор войск";
public const string EventDescription =
"Очки события даются за: победу в бою (+10), разграбление на карте мира (+15), бой на арене (+5), выполненное задание (+20), каждые 5 обученных воинов (+1).";
public static readonly int[] EventTiers = { 50, 150, 300, 500, 800 };
public static readonly RewardItem[][] EventTierRewards =
{
new[] { R(ResourceType.Gold, 500) },
new[] { R(ResourceType.Food, 1500), R(ResourceType.Wood, 1000) },
new[] { R(ResourceType.Gems, 50) },
new[] { R(ResourceType.Iron, 1500), R(ResourceType.Gold, 2000) },
new[] { R(ResourceType.Gems, 200) },
};
// ---------- Текст наград ----------
public static string RewardsText(RewardItem[] rewards)
{
if (rewards == null || rewards.Length == 0) return "";
var parts = new List<string>();
foreach (var r in rewards) parts.Add(Short(r.amount) + " " + ResName(r.type));
return string.Join(", ", parts.ToArray());
}
public static string Short(float value)
{
if (value >= 1000000f) return (value / 1000000f).ToString("0.#") + "M";
if (value >= 10000f) return (value / 1000f).ToString("0.#") + "K";
return Mathf.FloorToInt(value).ToString();
}
public static string FormatTime(double seconds)
{
if (seconds < 0) seconds = 0;
TimeSpan t = TimeSpan.FromSeconds(Math.Ceiling(seconds));
if (t.TotalDays >= 1) return string.Format("{0}д {1}ч", (int)t.TotalDays, t.Hours);
if (t.TotalHours >= 1) return string.Format("{0}ч {1:00}м", (int)t.TotalHours, t.Minutes);
return string.Format("{0:00}:{1:00}", t.Minutes, t.Seconds);
}
}