Merge branches 'master' and 'mods' of https://github.com/Anuken/Mindustry
# Conflicts: # core/src/io/anuke/mindustry/entities/type/FlyingUnit.java # gradle.properties
This commit is contained in:
@@ -22,20 +22,6 @@ public class Annotations{
|
|||||||
public @interface OverrideCallSuper {
|
public @interface OverrideCallSuper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Indicates that a method return or field can be null.*/
|
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface Nullable{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicates that a method return or field cannot be null.*/
|
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface NonNull{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Marks a class as serializable. */
|
/** Marks a class as serializable. */
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ load.map = Maps
|
|||||||
load.image = Images
|
load.image = Images
|
||||||
load.content = Content
|
load.content = Content
|
||||||
load.system = System
|
load.system = System
|
||||||
|
load.mod = Mods
|
||||||
|
|
||||||
stat.wave = Waves Defeated:[accent] {0}
|
stat.wave = Waves Defeated:[accent] {0}
|
||||||
stat.enemiesDestroyed = Enemies Destroyed:[accent] {0}
|
stat.enemiesDestroyed = Enemies Destroyed:[accent] {0}
|
||||||
@@ -64,6 +65,17 @@ uploadingpreviewfile = Uploading Preview File
|
|||||||
committingchanges = Comitting Changes
|
committingchanges = Comitting Changes
|
||||||
done = Done
|
done = Done
|
||||||
|
|
||||||
|
mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry Github or Discord.
|
||||||
|
mods.alpha = [scarlet](Alpha)
|
||||||
|
mods = Mods
|
||||||
|
mods.none = [LIGHT_GRAY]No mods found!
|
||||||
|
mod.enabled = [lightgray]Enabled
|
||||||
|
mod.disabled = [scarlet]Disabled
|
||||||
|
mod.requiresrestart = The game will now close to apply the mod changes.
|
||||||
|
mod.import = Import Mod
|
||||||
|
mod.remove.confirm = This mod will be deleted.
|
||||||
|
mod.author = [LIGHT_GRAY]Author:[] {0}
|
||||||
|
|
||||||
about.button = About
|
about.button = About
|
||||||
name = Name:
|
name = Name:
|
||||||
noname = Pick a[accent] player name[] first.
|
noname = Pick a[accent] player name[] first.
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ minimap = Мінімапа
|
|||||||
close = Закрити
|
close = Закрити
|
||||||
website = Веб-сайт
|
website = Веб-сайт
|
||||||
quit = Вихід
|
quit = Вихід
|
||||||
save.quit = Save & Quit
|
save.quit = Зберегти & Вийти
|
||||||
maps = Мапи
|
maps = Мапи
|
||||||
maps.browse = Перегляд мап
|
maps.browse = Перегляд мап
|
||||||
continue = Продовжити
|
continue = Продовжити
|
||||||
@@ -98,7 +98,7 @@ host = Сервер
|
|||||||
hosting = [accent]Відкриття сервера…
|
hosting = [accent]Відкриття сервера…
|
||||||
hosts.refresh = Оновити
|
hosts.refresh = Оновити
|
||||||
hosts.discovering = Пошук локальних ігор
|
hosts.discovering = Пошук локальних ігор
|
||||||
hosts.discovering.any = Discovering games
|
hosts.discovering.any = Пошук ігор
|
||||||
server.refreshing = Оновлення сервера
|
server.refreshing = Оновлення сервера
|
||||||
hosts.none = [lightgray]Локальних ігр не знайдено
|
hosts.none = [lightgray]Локальних ігр не знайдено
|
||||||
host.invalid = [scarlet]Не вдалося підключитися до сервера.
|
host.invalid = [scarlet]Не вдалося підключитися до сервера.
|
||||||
@@ -122,16 +122,16 @@ server.version = [lightgray]Версія: {0}
|
|||||||
server.custombuild = [yellow]Користувацька збірка
|
server.custombuild = [yellow]Користувацька збірка
|
||||||
confirmban = Ви дійсно хочете заблокувати цього гравця?
|
confirmban = Ви дійсно хочете заблокувати цього гравця?
|
||||||
confirmkick = Ви дійсно хочете викинути цього гравця?
|
confirmkick = Ви дійсно хочете викинути цього гравця?
|
||||||
confirmvotekick = Are you sure you want to vote-kick this player?
|
confirmvotekick = Ви дійсно хочете вигнати цього гравця за допомогою голосуванняr?
|
||||||
confirmunban = Ви дійсно хочете розблокувати цього гравця?
|
confirmunban = Ви дійсно хочете розблокувати цього гравця?
|
||||||
confirmadmin = Ви дійсно хочете зробити цього гравця адміністратором?
|
confirmadmin = Ви дійсно хочете зробити цього гравця адміністратором?
|
||||||
confirmunadmin = Ви дійсно хочете видалити статус адміністратора з цього гравця?
|
confirmunadmin = Ви дійсно хочете видалити статус адміністратора з цього гравця?
|
||||||
joingame.title = Приєднатися до гри
|
joingame.title = Приєднатися до гри
|
||||||
joingame.ip = IP:
|
joingame.ip = IP:
|
||||||
disconnect = Відключено.
|
disconnect = Відключено.
|
||||||
disconnect.error = Connection error.
|
disconnect.error = Помилка з’єднання.
|
||||||
disconnect.closed = Connection closed.
|
disconnect.closed = З'єднання закрито.
|
||||||
disconnect.timeout = Timed out.
|
disconnect.timeout = Час вийшов.
|
||||||
disconnect.data = Не вдалося завантажити дані світу!
|
disconnect.data = Не вдалося завантажити дані світу!
|
||||||
cantconnect = Не вдалося під’єднатися до гри ([accent]{0}[]).
|
cantconnect = Не вдалося під’єднатися до гри ([accent]{0}[]).
|
||||||
connecting = [accent]Підключення…
|
connecting = [accent]Підключення…
|
||||||
@@ -159,7 +159,7 @@ save.rename = Перейменувати
|
|||||||
save.rename.text = Нова назва:
|
save.rename.text = Нова назва:
|
||||||
selectslot = Виберіть збереження.
|
selectslot = Виберіть збереження.
|
||||||
slot = [accent]Слот {0}
|
slot = [accent]Слот {0}
|
||||||
editmessage = Edit Message
|
editmessage = Редагувати повідомлення
|
||||||
save.corrupted = [accent]Збережений файл пошкоджено або недійсний! \nЯкщо ви щойно оновили свою гру, це, мабуть, є зміною формату збереження та [scarlet] не є[] помилкою.
|
save.corrupted = [accent]Збережений файл пошкоджено або недійсний! \nЯкщо ви щойно оновили свою гру, це, мабуть, є зміною формату збереження та [scarlet] не є[] помилкою.
|
||||||
empty = <Порожньо>
|
empty = <Порожньо>
|
||||||
on = Увімкнено
|
on = Увімкнено
|
||||||
@@ -167,13 +167,14 @@ off = Вимкнено
|
|||||||
save.autosave = Автозбереження: {0}
|
save.autosave = Автозбереження: {0}
|
||||||
save.map = Мапа: {0}
|
save.map = Мапа: {0}
|
||||||
save.wave = Хвиля {0}
|
save.wave = Хвиля {0}
|
||||||
save.mode = Gamemode: {0}
|
save.mode = Режим гри: {0}
|
||||||
save.date = Останнє збереження
|
save.date = Останнє збереження
|
||||||
save.playtime = Час гри: {0}
|
save.playtime = Час гри: {0}
|
||||||
warning = Попередження
|
warning = Попередження
|
||||||
confirm = Підтвердження
|
confirm = Підтвердження
|
||||||
delete = Видалити
|
delete = Видалити
|
||||||
view.workshop = Переглянути в Майстерні
|
view.workshop = Переглянути в Майстерні
|
||||||
|
workshop.listing = Редагувати список Майстерні
|
||||||
ok = ОК
|
ok = ОК
|
||||||
open = Відкрити
|
open = Відкрити
|
||||||
customize = Налаштувати правила
|
customize = Налаштувати правила
|
||||||
@@ -211,10 +212,15 @@ map.nospawn.pvp = У цієї мапи немає ворожих ядер, в я
|
|||||||
map.nospawn.attack = У цієї мапи немає ворожих ядер, в яких гравець може з’явитися! Додайте [SCARLET]червоне[] ядро до цієї мапи в редакторі.
|
map.nospawn.attack = У цієї мапи немає ворожих ядер, в яких гравець може з’явитися! Додайте [SCARLET]червоне[] ядро до цієї мапи в редакторі.
|
||||||
map.invalid = Помилка завантаження мапи: пошкоджений або невірний файл мапи.
|
map.invalid = Помилка завантаження мапи: пошкоджений або невірний файл мапи.
|
||||||
map.publish.error = Помилка при опублікуванні мапи: {0}
|
map.publish.error = Помилка при опублікуванні мапи: {0}
|
||||||
|
map.update = Оновити мапу
|
||||||
|
map.load.error = Помилка отримання даних з Майстерню: {0}
|
||||||
|
map.missing = Цю карту було видалено або переміщено.\n[lightgray]Перелік у Майстерні автоматично від’єднано від мапи.
|
||||||
|
map.menu = Виберіть, що ви хочете зробити з цією мапою.
|
||||||
|
map.changelog = Список змік (необов’язково):
|
||||||
map.publish.confirm = Ви дійсно хочете опублікувати цю мапу?\n\n[lightgray]Переконайтеся, що спершу ви згодні з Ліцензійною угодою Steam, або ваші мапи не з’являться!
|
map.publish.confirm = Ви дійсно хочете опублікувати цю мапу?\n\n[lightgray]Переконайтеся, що спершу ви згодні з Ліцензійною угодою Steam, або ваші мапи не з’являться!
|
||||||
eula = Ліцензійна угода
|
eula = Ліцензійна угода
|
||||||
map.publish = Map published.
|
map.publish = Мапа опублікована.
|
||||||
map.publishing = [accent]Publishing map...
|
map.publishing = [accent]Публікації мапи...
|
||||||
editor.brush = Пензлик
|
editor.brush = Пензлик
|
||||||
editor.openin = Відкрити в редакторі
|
editor.openin = Відкрити в редакторі
|
||||||
editor.oregen = Генерація руд
|
editor.oregen = Генерація руд
|
||||||
@@ -222,7 +228,7 @@ editor.oregen.info = Генерація руд:
|
|||||||
editor.mapinfo = Інформація про мапу
|
editor.mapinfo = Інформація про мапу
|
||||||
editor.author = Автор:
|
editor.author = Автор:
|
||||||
editor.description = Опис:
|
editor.description = Опис:
|
||||||
editor.nodescription = A map must have a description of at least 4 characters before being published.
|
editor.nodescription = Мапа повинна мати щонаймеше 4 символи для публікації.
|
||||||
editor.waves = Хвилі:
|
editor.waves = Хвилі:
|
||||||
editor.rules = Правила:
|
editor.rules = Правила:
|
||||||
editor.generation = Генерація:
|
editor.generation = Генерація:
|
||||||
@@ -246,7 +252,7 @@ waves.invalid = Недійсні хвилі у буфері обміну.
|
|||||||
waves.copied = Хвилі скопійовані.
|
waves.copied = Хвилі скопійовані.
|
||||||
waves.none = Вороги не були встановлені.\nЗазначимо, що пусті хвилі будуть автоматично замінені звичайною хвилею.
|
waves.none = Вороги не були встановлені.\nЗазначимо, що пусті хвилі будуть автоматично замінені звичайною хвилею.
|
||||||
editor.default = [lightgray]<За замовчуванням>
|
editor.default = [lightgray]<За замовчуванням>
|
||||||
details = Details...
|
details = Деталі...
|
||||||
edit = Редагувати…
|
edit = Редагувати…
|
||||||
editor.name = Назва:
|
editor.name = Назва:
|
||||||
editor.spawn = Створити бойову одиницю
|
editor.spawn = Створити бойову одиницю
|
||||||
@@ -256,7 +262,7 @@ editor.errorload = Помилка завантаження зображення:
|
|||||||
editor.errorsave = Помилка збереження зображення:\n[accent]{0}
|
editor.errorsave = Помилка збереження зображення:\n[accent]{0}
|
||||||
editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це запрацює.\n\nЯкщо Ви хочете імпортувати застарілку мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі.
|
editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це запрацює.\n\nЯкщо Ви хочете імпортувати застарілку мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі.
|
||||||
editor.errorlegacy = Ця мапа занадто стара і використовує попередній формат мапи, який більше не підтримується.
|
editor.errorlegacy = Ця мапа занадто стара і використовує попередній формат мапи, який більше не підтримується.
|
||||||
editor.errornot = This is not a map file.
|
editor.errornot = Це не мапа.
|
||||||
editor.errorheader = Цей файл мапи недійсний або пошкоджений.
|
editor.errorheader = Цей файл мапи недійсний або пошкоджений.
|
||||||
editor.errorname = Мапа не має імені. Може Ви намагаєтеся завантажити збереження?
|
editor.errorname = Мапа не має імені. Може Ви намагаєтеся завантажити збереження?
|
||||||
editor.update = Оновити
|
editor.update = Оновити
|
||||||
@@ -289,7 +295,7 @@ editor.resizemap = Змінити розмір мапи
|
|||||||
editor.mapname = Назва мапи:
|
editor.mapname = Назва мапи:
|
||||||
editor.overwrite = [accent]Попередження!\nЦе перезаписує існуючу мапу.
|
editor.overwrite = [accent]Попередження!\nЦе перезаписує існуючу мапу.
|
||||||
editor.overwrite.confirm = [scarlet]Попередження![] Мапа з такою назвою вже існує. Ви впевнені, що хочете переписати її?
|
editor.overwrite.confirm = [scarlet]Попередження![] Мапа з такою назвою вже існує. Ви впевнені, що хочете переписати її?
|
||||||
editor.exists = A map with this name already exists.
|
editor.exists = Мапа за такою назвою вже існує.
|
||||||
editor.selectmap = Виберіть мапу для завантаження:
|
editor.selectmap = Виберіть мапу для завантаження:
|
||||||
toolmode.replace = Замінити
|
toolmode.replace = Замінити
|
||||||
toolmode.replace.description = Малює тільки\nна суцільних блоках.
|
toolmode.replace.description = Малює тільки\nна суцільних блоках.
|
||||||
@@ -369,7 +375,7 @@ launch.skip.confirm = Якщо Ви пропустите зараз, Ви не
|
|||||||
uncover = Розкрити
|
uncover = Розкрити
|
||||||
configure = Вивантажити конфігурацію
|
configure = Вивантажити конфігурацію
|
||||||
configure.locked = [lightgray]Можливість розблокувати вивантаження ресурсів буде доступна на {0}-тій хвилі.
|
configure.locked = [lightgray]Можливість розблокувати вивантаження ресурсів буде доступна на {0}-тій хвилі.
|
||||||
configure.invalid = Amount must be a number between 0 and {0}.
|
configure.invalid = Кількість повинна бути числом між 0 та {0}.
|
||||||
zone.unlocked = Зона «[lightgray]{0}» тепер розблокована.
|
zone.unlocked = Зона «[lightgray]{0}» тепер розблокована.
|
||||||
zone.requirement.complete = Ви досягли {0}-тої хвилі,\nВимоги до зони «{1}» виконані.
|
zone.requirement.complete = Ви досягли {0}-тої хвилі,\nВимоги до зони «{1}» виконані.
|
||||||
zone.config.complete = Ви досягли {0}-тої хвилі.\nМожливість вивантаження ресурсів тепер розблокована.
|
zone.config.complete = Ви досягли {0}-тої хвилі.\nМожливість вивантаження ресурсів тепер розблокована.
|
||||||
@@ -466,7 +472,7 @@ blocks.boosteffect = Прискорювальний ефект
|
|||||||
blocks.maxunits = Максимальна кількість активних одиниць
|
blocks.maxunits = Максимальна кількість активних одиниць
|
||||||
blocks.health = Здоров’я
|
blocks.health = Здоров’я
|
||||||
blocks.buildtime = Час будівництва
|
blocks.buildtime = Час будівництва
|
||||||
blocks.buildcost = Build Cost
|
blocks.buildcost = Вартість будування
|
||||||
blocks.inaccuracy = Розкид
|
blocks.inaccuracy = Розкид
|
||||||
blocks.shots = Постріли
|
blocks.shots = Постріли
|
||||||
blocks.reload = Постріли/секунду
|
blocks.reload = Постріли/секунду
|
||||||
@@ -475,7 +481,7 @@ bar.drilltierreq = Потребується кращий бур
|
|||||||
bar.drillspeed = Швидкість буріння: {0}/с
|
bar.drillspeed = Швидкість буріння: {0}/с
|
||||||
bar.efficiency = Ефективність: {0}%
|
bar.efficiency = Ефективність: {0}%
|
||||||
bar.powerbalance = Енергія: {0}/с
|
bar.powerbalance = Енергія: {0}/с
|
||||||
bar.powerstored = Stored: {0}/{1}
|
bar.powerstored = Зберігає: {0}/{1}
|
||||||
bar.poweramount = Енергія: {0}
|
bar.poweramount = Енергія: {0}
|
||||||
bar.poweroutput = Вихідна енергія: {0}
|
bar.poweroutput = Вихідна енергія: {0}
|
||||||
bar.items = Предмети: {0}
|
bar.items = Предмети: {0}
|
||||||
@@ -524,7 +530,7 @@ setting.antialias.name = Згладжування[lightgray] (потребує
|
|||||||
setting.indicators.name = Показувати у сторону ворогів та союзників
|
setting.indicators.name = Показувати у сторону ворогів та союзників
|
||||||
setting.autotarget.name = Авто-стрільба
|
setting.autotarget.name = Авто-стрільба
|
||||||
setting.keyboard.name = Миш+Керування з клавіатури
|
setting.keyboard.name = Миш+Керування з клавіатури
|
||||||
setting.touchscreen.name = Touchscreen Controls
|
setting.touchscreen.name = Керування сенсорним екраном
|
||||||
setting.fpscap.name = Максимальний FPS
|
setting.fpscap.name = Максимальний FPS
|
||||||
setting.fpscap.none = Необмежений
|
setting.fpscap.none = Необмежений
|
||||||
setting.fpscap.text = {0} FPS
|
setting.fpscap.text = {0} FPS
|
||||||
@@ -534,7 +540,7 @@ setting.difficulty.training = Навчання
|
|||||||
setting.difficulty.easy = Легка
|
setting.difficulty.easy = Легка
|
||||||
setting.difficulty.normal = Нормальна
|
setting.difficulty.normal = Нормальна
|
||||||
setting.difficulty.hard = Важка
|
setting.difficulty.hard = Важка
|
||||||
setting.difficulty.insane = Зачистка
|
setting.difficulty.insane = Неможлива
|
||||||
setting.difficulty.name = Складність:
|
setting.difficulty.name = Складність:
|
||||||
setting.screenshake.name = Тряска екрану
|
setting.screenshake.name = Тряска екрану
|
||||||
setting.effects.name = Ефекти
|
setting.effects.name = Ефекти
|
||||||
@@ -555,9 +561,10 @@ setting.sfxvol.name = Гучність звукових ефектів
|
|||||||
setting.mutesound.name = Заглушити звук
|
setting.mutesound.name = Заглушити звук
|
||||||
setting.crashreport.name = Відсилати анонімні звіти про аварійне завершення гри
|
setting.crashreport.name = Відсилати анонімні звіти про аварійне завершення гри
|
||||||
setting.savecreate.name = Автоматичне створення збережень
|
setting.savecreate.name = Автоматичне створення збережень
|
||||||
setting.publichost.name = Public Game Visibility
|
setting.publichost.name = Загальнодоступність гри
|
||||||
setting.chatopacity.name = Непрозорість чату
|
setting.chatopacity.name = Непрозорість чату
|
||||||
setting.playerchat.name = Відображати хмару чата над гравцями
|
setting.playerchat.name = Відображати хмару чата над гравцями
|
||||||
|
public.confirm = Ви хочете зробити цю гру загальнодоступною?\n[lightgray]Це можна змінити у Налаштування->Гра->Public Game Visibility.
|
||||||
uiscale.reset = Масштаб користувальницького інтерфейсу було змінено.\nНатисніть «ОК» для підтверждення цього масшатабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] …
|
uiscale.reset = Масштаб користувальницького інтерфейсу було змінено.\nНатисніть «ОК» для підтверждення цього масшатабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] …
|
||||||
uiscale.cancel = Скасувати & Вийти
|
uiscale.cancel = Скасувати & Вийти
|
||||||
setting.bloom.name = Світіння
|
setting.bloom.name = Світіння
|
||||||
@@ -567,7 +574,7 @@ category.general.name = Основне
|
|||||||
category.view.name = Перегляд
|
category.view.name = Перегляд
|
||||||
category.multiplayer.name = Мережева гра
|
category.multiplayer.name = Мережева гра
|
||||||
command.attack = Атакувати
|
command.attack = Атакувати
|
||||||
command.rally = Rally
|
command.rally = Точка збору
|
||||||
command.retreat = Відступити
|
command.retreat = Відступити
|
||||||
keybind.gridMode.name = Вибрати блок
|
keybind.gridMode.name = Вибрати блок
|
||||||
keybind.gridModeShift.name = Вибрати категорію
|
keybind.gridModeShift.name = Вибрати категорію
|
||||||
@@ -604,6 +611,7 @@ mode.survival.name = Хвилі
|
|||||||
mode.survival.description = Звичайний режим. В цьому режимі треба самим добувати ресурси та хвилі йдуть автоматично.\n[gray]Потребуються точки появи ворогів для гри.
|
mode.survival.description = Звичайний режим. В цьому режимі треба самим добувати ресурси та хвилі йдуть автоматично.\n[gray]Потребуються точки появи ворогів для гри.
|
||||||
mode.sandbox.name = Пісочниця
|
mode.sandbox.name = Пісочниця
|
||||||
mode.sandbox.description = В режимі «Пісочниця» незкінченні ресурси(але їх все одно можно добувати) та хвилі йдуть за вашим бажанням.
|
mode.sandbox.description = В режимі «Пісочниця» незкінченні ресурси(але їх все одно можно добувати) та хвилі йдуть за вашим бажанням.
|
||||||
|
mode.editor.name = Редактор
|
||||||
mode.pvp.name = PVP
|
mode.pvp.name = PVP
|
||||||
mode.pvp.description = боріться проти інших гравців.\n[gray]Для гри потрібно принаймні 2 ядра різного кольору на мапі.
|
mode.pvp.description = боріться проти інших гравців.\n[gray]Для гри потрібно принаймні 2 ядра різного кольору на мапі.
|
||||||
mode.attack.name = Атака
|
mode.attack.name = Атака
|
||||||
@@ -784,13 +792,13 @@ block.hail.name = Град
|
|||||||
block.lancer.name = Списоносець
|
block.lancer.name = Списоносець
|
||||||
block.conveyor.name = Конвеєр
|
block.conveyor.name = Конвеєр
|
||||||
block.titanium-conveyor.name = Титановий конвеєр
|
block.titanium-conveyor.name = Титановий конвеєр
|
||||||
block.armored-conveyor.name = Armored Conveyor
|
block.armored-conveyor.name = Броньований конвеєр
|
||||||
block.armored-conveyor.description = Moves items at the same speed as titanium conveyors, but possesses more armor. Does not accept inputs from the sides from anything but other conveyors.
|
block.armored-conveyor.description = Переміщує предмети з тією ж швидкістю, як і титанові конвеєри, але має більше міцності. Не приймає введення з боків ні з чого, крім інших конвеєрів.
|
||||||
block.junction.name = Перехрестя
|
block.junction.name = Перехрестя
|
||||||
block.router.name = Маршрутизатор
|
block.router.name = Маршрутизатор
|
||||||
block.distributor.name = Розподілювач
|
block.distributor.name = Розподілювач
|
||||||
block.sorter.name = Сортувальник
|
block.sorter.name = Сортувальник
|
||||||
block.message.name = Message
|
block.message.name = Повідомлення
|
||||||
block.overflow-gate.name = Надмірний затвор
|
block.overflow-gate.name = Надмірний затвор
|
||||||
block.silicon-smelter.name = Кремнієвий плавильний завод
|
block.silicon-smelter.name = Кремнієвий плавильний завод
|
||||||
block.phase-weaver.name = Фазовий ткач
|
block.phase-weaver.name = Фазовий ткач
|
||||||
@@ -879,8 +887,8 @@ block.overdrive-projector.name = Сверхприводний проектор
|
|||||||
block.force-projector.name = Силовий проектор
|
block.force-projector.name = Силовий проектор
|
||||||
block.arc.name = Дуга
|
block.arc.name = Дуга
|
||||||
block.rtg-generator.name = Радіоізотопний термоелектричний генератор
|
block.rtg-generator.name = Радіоізотопний термоелектричний генератор
|
||||||
block.spectre.name = Мара
|
block.spectre.name = Спектр
|
||||||
block.meltdown.name = Катастрофа
|
block.meltdown.name = Випалювач
|
||||||
block.container.name = Склад
|
block.container.name = Склад
|
||||||
block.launch-pad.name = Стартовий майданчик
|
block.launch-pad.name = Стартовий майданчик
|
||||||
block.launch-pad-large.name = Великий стартовий майданчик
|
block.launch-pad-large.name = Великий стартовий майданчик
|
||||||
@@ -892,7 +900,7 @@ team.derelict.name = Залишена
|
|||||||
team.green.name = Зелена
|
team.green.name = Зелена
|
||||||
team.purple.name = Фіолетова
|
team.purple.name = Фіолетова
|
||||||
unit.spirit.name = Ремонтувальний дрон «Привид»
|
unit.spirit.name = Ремонтувальний дрон «Привид»
|
||||||
unit.draug.name = Draug Miner Drone
|
unit.draug.name = Добувний дрон «Драугр»
|
||||||
unit.phantom.name = Будівельний дрон «Фантом»
|
unit.phantom.name = Будівельний дрон «Фантом»
|
||||||
unit.dagger.name = Кинджал
|
unit.dagger.name = Кинджал
|
||||||
unit.crawler.name = Камікадзе
|
unit.crawler.name = Камікадзе
|
||||||
@@ -907,7 +915,7 @@ unit.eradicator.name = Викорінювач
|
|||||||
unit.lich.name = Лич
|
unit.lich.name = Лич
|
||||||
unit.reaper.name = Жнець
|
unit.reaper.name = Жнець
|
||||||
tutorial.next = [lightgray]<Натисніть для продовження>
|
tutorial.next = [lightgray]<Натисніть для продовження>
|
||||||
tutorial.intro = Ви розпочали[scarlet] навчання по Mindustry.[]\nРозпочність з[accent] видобування міді[]. Натисніть на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді
|
tutorial.intro = Ви розпочали[scarlet] навчання по Mindustry.[]\nРозпочність з[accent] видобування міді[]. Використовуйте [[WASD] для руху, а потім натисність на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді
|
||||||
tutorial.drill = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку свердла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\n[accent]Натисніть ПКМ[], щоб зупинити будування.
|
tutorial.drill = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку свердла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\n[accent]Натисніть ПКМ[], щоб зупинити будування.
|
||||||
tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent] галочку[] нижче, щоб підтвердити розміщення to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent] галочку[] нижче, щоб підтвердити розміщення to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
||||||
tutorial.blockinfo = Кожен блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли Ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура прямо зараз.[]
|
tutorial.blockinfo = Кожен блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли Ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура прямо зараз.[]
|
||||||
@@ -965,7 +973,7 @@ unit.eruptor.description = Важкий мех, призначеней для з
|
|||||||
unit.wraith.description = Швидкий перехоплювач, який використовується для тактики «атакуй і біжи». Пріоритет — енергетичні генератори.
|
unit.wraith.description = Швидкий перехоплювач, який використовується для тактики «атакуй і біжи». Пріоритет — енергетичні генератори.
|
||||||
unit.ghoul.description = Важкий килимовий бомбардувальник. Пробиває ворожі структури, орієнтуючись на віжливу інфраструктуру.
|
unit.ghoul.description = Важкий килимовий бомбардувальник. Пробиває ворожі структури, орієнтуючись на віжливу інфраструктуру.
|
||||||
unit.revenant.description = Важкий ракетний масив.
|
unit.revenant.description = Важкий ракетний масив.
|
||||||
block.message.description = Stores a message. Used for communication between allies.
|
block.message.description = Зберігає повідомлення. Використовується для комунікаціх між союзниками.
|
||||||
block.graphite-press.description = Стискає шматки вугілля в чисті аркуші графіту.
|
block.graphite-press.description = Стискає шматки вугілля в чисті аркуші графіту.
|
||||||
block.multi-press.description = Модернізована версія графітового преса. Використовує воду та енергію для швидкої та ефективної переробки вугілля.
|
block.multi-press.description = Модернізована версія графітового преса. Використовує воду та енергію для швидкої та ефективної переробки вугілля.
|
||||||
block.silicon-smelter.description = Змішує пісок з чистим вугіллям. Виробляє кремній.
|
block.silicon-smelter.description = Змішує пісок з чистим вугіллям. Виробляє кремній.
|
||||||
@@ -1050,7 +1058,7 @@ block.core-foundation.description = Друга версія ядра. Краще
|
|||||||
block.core-nucleus.description = Третя і остання ітерація капсули ядра. Надзвичайно добре броньований. Зберігає величезні обсяги ресурсів.
|
block.core-nucleus.description = Третя і остання ітерація капсули ядра. Надзвичайно добре броньований. Зберігає величезні обсяги ресурсів.
|
||||||
block.vault.description = Зберігає велику кількість предметів кожного типу. Блок розвантажувача може використовуватися для отримання предметів із сховища.
|
block.vault.description = Зберігає велику кількість предметів кожного типу. Блок розвантажувача може використовуватися для отримання предметів із сховища.
|
||||||
block.container.description = Зберігає велику кількість предметів кожного типу. Блок розвантажувача може використовуватися для отримання предметів із сховища.
|
block.container.description = Зберігає велику кількість предметів кожного типу. Блок розвантажувача може використовуватися для отримання предметів із сховища.
|
||||||
block.unloader.description = Вивантажує предмети з контейнера, склепіння або серцевини на конвеєр або безпосередньо в сусідній блок. Тип предмета для завантаження можна змінити, натиснувши на блок.
|
block.unloader.description = Вивантажує предмети з блока, який не переміщує предмети, на конвеєр або безпосередньо в сусідній блок. Тип предмета для завантаження можна змінити, натиснувши на блок.
|
||||||
block.launch-pad.description = Запускає партії предметів без необхідності запуску ядра.
|
block.launch-pad.description = Запускає партії предметів без необхідності запуску ядра.
|
||||||
block.launch-pad-large.description = Покращена версія стартового майданчика. Зберігає більше предметів. Запускається частіше.
|
block.launch-pad-large.description = Покращена версія стартового майданчика. Зберігає більше предметів. Запускається частіше.
|
||||||
block.duo.description = Невелика дешева башта. Корисна проти наземних одиниць.
|
block.duo.description = Невелика дешева башта. Корисна проти наземних одиниць.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import io.anuke.mindustry.game.EventType.*;
|
|||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.*;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
|
|
||||||
import static io.anuke.arc.Core.*;
|
import static io.anuke.arc.Core.*;
|
||||||
@@ -43,6 +44,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
assets.load("sprites/error.png", Texture.class);
|
assets.load("sprites/error.png", Texture.class);
|
||||||
atlas = TextureAtlas.blankAtlas();
|
atlas = TextureAtlas.blankAtlas();
|
||||||
Vars.net = new Net(platform.getNet());
|
Vars.net = new Net(platform.getNet());
|
||||||
|
Vars.mods = new Mods();
|
||||||
|
|
||||||
UI.loadSystemCursors();
|
UI.loadSystemCursors();
|
||||||
|
|
||||||
@@ -71,6 +73,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
add(netServer = new NetServer());
|
add(netServer = new NetServer());
|
||||||
add(netClient = new NetClient());
|
add(netClient = new NetClient());
|
||||||
|
|
||||||
|
assets.load(mods);
|
||||||
|
|
||||||
assets.loadRun("contentinit", ContentLoader.class, () -> {
|
assets.loadRun("contentinit", ContentLoader.class, () -> {
|
||||||
content.init();
|
content.init();
|
||||||
content.load();
|
content.load();
|
||||||
@@ -108,6 +112,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
listener.init();
|
listener.init();
|
||||||
}
|
}
|
||||||
super.resize(graphics.getWidth(), graphics.getHeight());
|
super.resize(graphics.getWidth(), graphics.getHeight());
|
||||||
|
mods.each(Mod::init);
|
||||||
finished = true;
|
finished = true;
|
||||||
Events.fire(new ClientLoadEvent());
|
Events.fire(new ClientLoadEvent());
|
||||||
}
|
}
|
||||||
@@ -182,7 +187,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
|
|
||||||
if(assets.getCurrentLoading() != null){
|
if(assets.getCurrentLoading() != null){
|
||||||
String name = assets.getCurrentLoading().fileName.toLowerCase();
|
String name = assets.getCurrentLoading().fileName.toLowerCase();
|
||||||
String key = name.contains("content") ? "content" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system";
|
String key = name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system";
|
||||||
font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center);
|
font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ import io.anuke.mindustry.game.*;
|
|||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.input.*;
|
import io.anuke.mindustry.input.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.*;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.plugin.*;
|
|
||||||
import io.anuke.mindustry.world.blocks.defense.ForceProjector.*;
|
import io.anuke.mindustry.world.blocks.defense.ForceProjector.*;
|
||||||
|
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static io.anuke.arc.Core.settings;
|
import static io.anuke.arc.Core.*;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class Vars implements Loadable{
|
public class Vars implements Loadable{
|
||||||
@@ -120,8 +120,8 @@ public class Vars implements Loadable{
|
|||||||
public static FileHandle tmpDirectory;
|
public static FileHandle tmpDirectory;
|
||||||
/** data subdirectory used for saves */
|
/** data subdirectory used for saves */
|
||||||
public static FileHandle saveDirectory;
|
public static FileHandle saveDirectory;
|
||||||
/** data subdirectory used for plugins */
|
/** data subdirectory used for mods */
|
||||||
public static FileHandle pluginDirectory;
|
public static FileHandle modDirectory;
|
||||||
/** map file extension */
|
/** map file extension */
|
||||||
public static final String mapExtension = "msav";
|
public static final String mapExtension = "msav";
|
||||||
/** save file extension */
|
/** save file extension */
|
||||||
@@ -130,6 +130,7 @@ public class Vars implements Loadable{
|
|||||||
/** list of all locales that can be switched to */
|
/** list of all locales that can be switched to */
|
||||||
public static Locale[] locales;
|
public static Locale[] locales;
|
||||||
|
|
||||||
|
public static FileTree filet;
|
||||||
public static Net net;
|
public static Net net;
|
||||||
public static ContentLoader content;
|
public static ContentLoader content;
|
||||||
public static GameState state;
|
public static GameState state;
|
||||||
@@ -138,7 +139,7 @@ public class Vars implements Loadable{
|
|||||||
public static DefaultWaves defaultWaves;
|
public static DefaultWaves defaultWaves;
|
||||||
public static LoopControl loops;
|
public static LoopControl loops;
|
||||||
public static Platform platform = new Platform(){};
|
public static Platform platform = new Platform(){};
|
||||||
public static Plugins plugins;
|
public static Mods mods;
|
||||||
|
|
||||||
public static World world;
|
public static World world;
|
||||||
public static Maps maps;
|
public static Maps maps;
|
||||||
@@ -193,6 +194,10 @@ public class Vars implements Loadable{
|
|||||||
|
|
||||||
Version.init();
|
Version.init();
|
||||||
|
|
||||||
|
filet = new FileTree();
|
||||||
|
if(mods == null){
|
||||||
|
mods = new Mods();
|
||||||
|
}
|
||||||
content = new ContentLoader();
|
content = new ContentLoader();
|
||||||
loops = new LoopControl();
|
loops = new LoopControl();
|
||||||
defaultWaves = new DefaultWaves();
|
defaultWaves = new DefaultWaves();
|
||||||
@@ -240,8 +245,11 @@ public class Vars implements Loadable{
|
|||||||
mapPreviewDirectory = dataDirectory.child("previews/");
|
mapPreviewDirectory = dataDirectory.child("previews/");
|
||||||
saveDirectory = dataDirectory.child("saves/");
|
saveDirectory = dataDirectory.child("saves/");
|
||||||
tmpDirectory = dataDirectory.child("tmp/");
|
tmpDirectory = dataDirectory.child("tmp/");
|
||||||
pluginDirectory = dataDirectory.child("plugins/");
|
modDirectory = dataDirectory.child("mods/");
|
||||||
|
|
||||||
|
modDirectory.mkdirs();
|
||||||
|
|
||||||
|
mods.load();
|
||||||
maps.load();
|
maps.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.collection.*;
|
|||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.async.*;
|
import io.anuke.arc.util.async.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
@@ -32,7 +33,8 @@ public class Pathfinder implements Runnable{
|
|||||||
/** handles task scheduling on the update thread. */
|
/** handles task scheduling on the update thread. */
|
||||||
private TaskQueue queue = new TaskQueue();
|
private TaskQueue queue = new TaskQueue();
|
||||||
/** current pathfinding thread */
|
/** current pathfinding thread */
|
||||||
private @Nullable Thread thread;
|
private @Nullable
|
||||||
|
Thread thread;
|
||||||
|
|
||||||
public Pathfinder(){
|
public Pathfinder(){
|
||||||
Events.on(WorldLoadEvent.class, event -> {
|
Events.on(WorldLoadEvent.class, event -> {
|
||||||
@@ -92,7 +94,11 @@ public class Pathfinder implements Runnable{
|
|||||||
|
|
||||||
int x = tile.x, y = tile.y;
|
int x = tile.x, y = tile.y;
|
||||||
|
|
||||||
tile.getLinkedTiles(t -> tiles[t.x][t.y] = packTile(t));
|
tile.getLinkedTiles(t -> {
|
||||||
|
if(Structs.inBounds(t.x, t.y, tiles)){
|
||||||
|
tiles[t.x][t.y] = packTile(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//can't iterate through array so use the map, which should not lead to problems
|
//can't iterate through array so use the map, which should not lead to problems
|
||||||
for(PathData[] arr : pathMap){
|
for(PathData[] arr : pathMap){
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class WaveSpawner{
|
|||||||
for(SpawnGroup group : state.rules.spawns){
|
for(SpawnGroup group : state.rules.spawns){
|
||||||
int spawned = group.getUnitsSpawned(state.wave - 1);
|
int spawned = group.getUnitsSpawned(state.wave - 1);
|
||||||
|
|
||||||
if(group.type.isFlying){
|
if(group.type.flying){
|
||||||
float spread = margin / 1.5f;
|
float spread = margin / 1.5f;
|
||||||
|
|
||||||
eachFlyerSpawn((spawnX, spawnY) -> {
|
eachFlyerSpawn((spawnX, spawnY) -> {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class UnitTypes implements ContentList{
|
|||||||
@Override
|
@Override
|
||||||
public void load(){
|
public void load(){
|
||||||
draug = new UnitType("draug", Draug.class, Draug::new){{
|
draug = new UnitType("draug", Draug.class, Draug::new){{
|
||||||
isFlying = true;
|
flying = true;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
speed = 0.3f;
|
speed = 0.3f;
|
||||||
maxVelocity = 1.2f;
|
maxVelocity = 1.2f;
|
||||||
@@ -33,7 +33,7 @@ public class UnitTypes implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
spirit = new UnitType("spirit", Spirit.class, Spirit::new){{
|
spirit = new UnitType("spirit", Spirit.class, Spirit::new){{
|
||||||
isFlying = true;
|
flying = true;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
speed = 0.4f;
|
speed = 0.4f;
|
||||||
maxVelocity = 1.6f;
|
maxVelocity = 1.6f;
|
||||||
@@ -54,7 +54,7 @@ public class UnitTypes implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
phantom = new UnitType("phantom", Phantom.class, Phantom::new){{
|
phantom = new UnitType("phantom", Phantom.class, Phantom::new){{
|
||||||
isFlying = true;
|
flying = true;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
mass = 2f;
|
mass = 2f;
|
||||||
speed = 0.45f;
|
speed = 0.45f;
|
||||||
@@ -244,7 +244,7 @@ public class UnitTypes implements ContentList{
|
|||||||
maxVelocity = 1.9f;
|
maxVelocity = 1.9f;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
mass = 1.5f;
|
mass = 1.5f;
|
||||||
isFlying = true;
|
flying = true;
|
||||||
health = 75;
|
health = 75;
|
||||||
engineOffset = 5.5f;
|
engineOffset = 5.5f;
|
||||||
range = 140f;
|
range = 140f;
|
||||||
@@ -264,7 +264,7 @@ public class UnitTypes implements ContentList{
|
|||||||
maxVelocity = 1.4f;
|
maxVelocity = 1.4f;
|
||||||
mass = 3f;
|
mass = 3f;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
isFlying = true;
|
flying = true;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
engineOffset = 7.8f;
|
engineOffset = 7.8f;
|
||||||
range = 140f;
|
range = 140f;
|
||||||
@@ -291,7 +291,7 @@ public class UnitTypes implements ContentList{
|
|||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
range = 80f;
|
range = 80f;
|
||||||
shootCone = 40f;
|
shootCone = 40f;
|
||||||
isFlying = true;
|
flying = true;
|
||||||
rotateWeapon = true;
|
rotateWeapon = true;
|
||||||
engineOffset = 12f;
|
engineOffset = 12f;
|
||||||
engineSize = 3f;
|
engineSize = 3f;
|
||||||
@@ -322,7 +322,7 @@ public class UnitTypes implements ContentList{
|
|||||||
drag = 0.02f;
|
drag = 0.02f;
|
||||||
range = 80f;
|
range = 80f;
|
||||||
shootCone = 20f;
|
shootCone = 20f;
|
||||||
isFlying = true;
|
flying = true;
|
||||||
rotateWeapon = true;
|
rotateWeapon = true;
|
||||||
engineOffset = 21;
|
engineOffset = 21;
|
||||||
engineSize = 5.3f;
|
engineSize = 5.3f;
|
||||||
@@ -355,7 +355,7 @@ public class UnitTypes implements ContentList{
|
|||||||
drag = 0.02f;
|
drag = 0.02f;
|
||||||
range = 80f;
|
range = 80f;
|
||||||
shootCone = 30f;
|
shootCone = 30f;
|
||||||
isFlying = true;
|
flying = true;
|
||||||
rotateWeapon = true;
|
rotateWeapon = true;
|
||||||
engineOffset = 40;
|
engineOffset = 40;
|
||||||
engineSize = 7.3f;
|
engineSize = 7.3f;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import io.anuke.mindustry.type.*;
|
|||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
|
|
||||||
import static io.anuke.arc.Core.files;
|
import static io.anuke.arc.Core.files;
|
||||||
|
import static io.anuke.mindustry.Vars.mods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all game content.
|
* Loads all game content.
|
||||||
@@ -57,6 +58,23 @@ public class ContentLoader{
|
|||||||
list.load();
|
list.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupMapping();
|
||||||
|
|
||||||
|
if(mods != null){
|
||||||
|
mods.loadContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMapping();
|
||||||
|
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMapping(){
|
||||||
|
|
||||||
|
for(ContentType type : ContentType.values()){
|
||||||
|
contentNameMap[type.ordinal()].clear();
|
||||||
|
}
|
||||||
|
|
||||||
for(ContentType type : ContentType.values()){
|
for(ContentType type : ContentType.values()){
|
||||||
|
|
||||||
for(Content c : contentMap[type.ordinal()]){
|
for(Content c : contentMap[type.ordinal()]){
|
||||||
@@ -79,8 +97,6 @@ public class ContentLoader{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logs content statistics.*/
|
/** Logs content statistics.*/
|
||||||
|
|||||||
23
core/src/io/anuke/mindustry/core/FileTree.java
Normal file
23
core/src/io/anuke/mindustry/core/FileTree.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package io.anuke.mindustry.core;
|
||||||
|
|
||||||
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
|
||||||
|
/** Handles files in a modded context. */
|
||||||
|
public class FileTree{
|
||||||
|
private ObjectMap<String, FileHandle> files = new ObjectMap<>();
|
||||||
|
|
||||||
|
public void addFile(FileHandle f){
|
||||||
|
files.put(f.path(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets an asset file.*/
|
||||||
|
public FileHandle get(String path){
|
||||||
|
if(files.containsKey(path)){
|
||||||
|
return files.get(path);
|
||||||
|
}else{
|
||||||
|
return Core.files.internal(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -200,6 +200,11 @@ public class NetServer implements ApplicationListener{
|
|||||||
registerCommands();
|
registerCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(){
|
||||||
|
mods.each(mod -> mod.registerClientCommands(clientCommands));
|
||||||
|
}
|
||||||
|
|
||||||
private void registerCommands(){
|
private void registerCommands(){
|
||||||
clientCommands.<Player>register("help", "[page]", "Lists all commands.", (args, player) -> {
|
clientCommands.<Player>register("help", "[page]", "Lists all commands.", (args, player) -> {
|
||||||
if(args.length > 0 && !Strings.canParseInt(args[0])){
|
if(args.length > 0 && !Strings.canParseInt(args[0])){
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
public DeployDialog deploy;
|
public DeployDialog deploy;
|
||||||
public TechTreeDialog tech;
|
public TechTreeDialog tech;
|
||||||
public MinimapDialog minimap;
|
public MinimapDialog minimap;
|
||||||
|
public ModsDialog mods;
|
||||||
|
|
||||||
public Cursor drillCursor, unloadCursor;
|
public Cursor drillCursor, unloadCursor;
|
||||||
|
|
||||||
@@ -222,6 +223,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
deploy = new DeployDialog();
|
deploy = new DeployDialog();
|
||||||
tech = new TechTreeDialog();
|
tech = new TechTreeDialog();
|
||||||
minimap = new MinimapDialog();
|
minimap = new MinimapDialog();
|
||||||
|
mods = new ModsDialog();
|
||||||
|
|
||||||
Group group = Core.scene.root;
|
Group group = Core.scene.root;
|
||||||
|
|
||||||
@@ -410,6 +412,18 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showOkText(String title, String text, Runnable confirmed){
|
||||||
|
FloatingDialog dialog = new FloatingDialog(title);
|
||||||
|
dialog.cont.add(text).width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||||
|
dialog.buttons.defaults().size(200f, 54f).pad(2f);
|
||||||
|
dialog.setFillParent(false);
|
||||||
|
dialog.buttons.addButton("$ok", () -> {
|
||||||
|
dialog.hide();
|
||||||
|
confirmed.run();
|
||||||
|
});
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
public String formatAmount(int number){
|
public String formatAmount(int number){
|
||||||
if(number >= 1000000){
|
if(number >= 1000000){
|
||||||
return Strings.fixed(number / 1000000f, 1) + "[gray]mil[]";
|
return Strings.fixed(number / 1000000f, 1) + "[gray]mil[]";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package io.anuke.mindustry.core;
|
package io.anuke.mindustry.core;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
@@ -82,7 +82,8 @@ public class World{
|
|||||||
return height()*tilesize;
|
return height()*tilesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Tile tile(int pos){
|
public @Nullable
|
||||||
|
Tile tile(int pos){
|
||||||
return tiles == null ? null : tile(Pos.x(pos), Pos.y(pos));
|
return tiles == null ? null : tile(Pos.x(pos), Pos.y(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.arc.files.*;
|
||||||
@@ -16,6 +15,7 @@ import io.anuke.arc.scene.style.*;
|
|||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
@@ -24,7 +24,7 @@ import io.anuke.mindustry.gen.*;
|
|||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
import io.anuke.mindustry.ui.Styles;
|
import io.anuke.mindustry.ui.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.*;
|
import io.anuke.mindustry.ui.dialogs.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
|
|||||||
@@ -47,10 +47,8 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
|||||||
@Remote(called = Loc.server)
|
@Remote(called = Loc.server)
|
||||||
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
|
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
|
||||||
if(tile == null || tile.entity == null || tile.entity.items == null) return;
|
if(tile == null || tile.entity == null || tile.entity.items == null) return;
|
||||||
if(!Units.canInteract(player, tile)) return;
|
|
||||||
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
||||||
Time.run(i * 3, () -> create(item, x, y, tile, () -> {
|
Time.run(i * 3, () -> create(item, x, y, tile, () -> {}));
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
tile.entity.items.add(item, amount);
|
tile.entity.items.add(item, amount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.traits;
|
package io.anuke.mindustry.entities.traits;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.Queue;
|
import io.anuke.arc.collection.Queue;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
@@ -8,6 +7,7 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
@@ -200,7 +200,8 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
* Return the build requests currently active, or the one at the top of the queue.
|
* Return the build requests currently active, or the one at the top of the queue.
|
||||||
* May return null.
|
* May return null.
|
||||||
*/
|
*/
|
||||||
default @Nullable BuildRequest buildRequest(){
|
default @Nullable
|
||||||
|
BuildRequest buildRequest(){
|
||||||
return buildQueue().size == 0 ? null : buildQueue().first();
|
return buildQueue().size == 0 ? null : buildQueue().first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
@@ -93,7 +94,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Tile getSpawner(){
|
public @Nullable
|
||||||
|
Tile getSpawner(){
|
||||||
return world.tile(spawner);
|
return world.tile(spawner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +265,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFlying(){
|
public boolean isFlying(){
|
||||||
return type.isFlying;
|
return type.flying;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import io.anuke.arc.math.geom.*;
|
|||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.pooling.*;
|
import io.anuke.arc.util.pooling.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
@@ -48,7 +49,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
|||||||
public float baseRotation;
|
public float baseRotation;
|
||||||
public float pointerX, pointerY;
|
public float pointerX, pointerY;
|
||||||
public String name = "noname";
|
public String name = "noname";
|
||||||
public @Nullable String uuid, usid;
|
public @Nullable
|
||||||
|
String uuid, usid;
|
||||||
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping;
|
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping;
|
||||||
public float boostHeat, shootHeat, destructTime;
|
public float boostHeat, shootHeat, destructTime;
|
||||||
public boolean achievedFlight;
|
public boolean achievedFlight;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.anuke.arc.collection.ObjectSet;
|
|||||||
import io.anuke.arc.math.geom.Point2;
|
import io.anuke.arc.math.geom.Point2;
|
||||||
import io.anuke.arc.math.geom.Vector2;
|
import io.anuke.arc.math.geom.Vector2;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.entities.EntityGroup;
|
import io.anuke.mindustry.entities.EntityGroup;
|
||||||
import io.anuke.mindustry.entities.traits.HealthTrait;
|
import io.anuke.mindustry.entities.traits.HealthTrait;
|
||||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||||
@@ -42,7 +43,8 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
private boolean dead = false;
|
private boolean dead = false;
|
||||||
private boolean sleeping;
|
private boolean sleeping;
|
||||||
private float sleepTime;
|
private float sleepTime;
|
||||||
private @Nullable SoundLoop sound;
|
private @Nullable
|
||||||
|
SoundLoop sound;
|
||||||
|
|
||||||
@Remote(called = Loc.server, unreliable = true)
|
@Remote(called = Loc.server, unreliable = true)
|
||||||
public static void onTileDamage(Tile tile, float health){
|
public static void onTileDamage(Tile tile, float health){
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
@@ -9,6 +8,7 @@ import io.anuke.arc.math.*;
|
|||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.effect.*;
|
import io.anuke.mindustry.entities.effect.*;
|
||||||
@@ -234,7 +234,8 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable TileEntity getClosestCore(){
|
public @Nullable
|
||||||
|
TileEntity getClosestCore(){
|
||||||
TeamData data = state.teams.get(team);
|
TeamData data = state.teams.get(team);
|
||||||
|
|
||||||
Tile tile = Geometry.findClosest(x, y, data.cores);
|
Tile tile = Geometry.findClosest(x, y, data.cores);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.entities.type.base;
|
|||||||
|
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.math.geom.Geometry;
|
import io.anuke.arc.math.geom.Geometry;
|
||||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
|
||||||
import io.anuke.mindustry.entities.units.*;
|
import io.anuke.mindustry.entities.units.*;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
|
||||||
|
|
||||||
public class Crawler extends GroundUnit{
|
public class Crawler extends GroundUnit{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
|
||||||
|
|
||||||
public class Dagger extends GroundUnit{
|
public class Dagger extends GroundUnit{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
|
||||||
|
|
||||||
public class Eruptor extends GroundUnit{
|
public class Eruptor extends GroundUnit{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
@@ -8,6 +8,7 @@ import io.anuke.arc.util.*;
|
|||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.bullet.*;
|
import io.anuke.mindustry.entities.bullet.*;
|
||||||
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.entities.units.*;
|
import io.anuke.mindustry.entities.units.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
@@ -15,7 +16,7 @@ import io.anuke.mindustry.world.meta.*;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public abstract class FlyingUnit extends BaseUnit{
|
public class FlyingUnit extends BaseUnit{
|
||||||
protected float[] weaponAngles = {0,0};
|
protected float[] weaponAngles = {0,0};
|
||||||
|
|
||||||
protected final UnitState
|
protected final UnitState
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
|
||||||
|
|
||||||
public class Fortress extends GroundUnit{
|
public class Fortress extends GroundUnit{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
|
||||||
|
|
||||||
public class Ghoul extends FlyingUnit{
|
public class Ghoul extends FlyingUnit{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
@@ -9,6 +9,7 @@ import io.anuke.mindustry.*;
|
|||||||
import io.anuke.mindustry.ai.Pathfinder.*;
|
import io.anuke.mindustry.ai.Pathfinder.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.bullet.*;
|
import io.anuke.mindustry.entities.bullet.*;
|
||||||
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.entities.units.*;
|
import io.anuke.mindustry.entities.units.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
@@ -18,7 +19,7 @@ import io.anuke.mindustry.world.meta.*;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public abstract class GroundUnit extends BaseUnit{
|
public class GroundUnit extends BaseUnit{
|
||||||
protected static Vector2 vec = new Vector2();
|
protected static Vector2 vec = new Vector2();
|
||||||
|
|
||||||
protected float walkTime;
|
protected float walkTime;
|
||||||
@@ -4,7 +4,6 @@ import io.anuke.arc.graphics.g2d.Draw;
|
|||||||
import io.anuke.arc.math.Angles;
|
import io.anuke.arc.math.Angles;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.mindustry.entities.Units;
|
import io.anuke.mindustry.entities.Units;
|
||||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
|
||||||
|
|
||||||
public class Revenant extends FlyingUnit{
|
public class Revenant extends FlyingUnit{
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
|
||||||
|
|
||||||
public class Titan extends GroundUnit{
|
public class Titan extends GroundUnit{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.anuke.mindustry.entities.type.base;
|
package io.anuke.mindustry.entities.type.base;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
|
||||||
|
|
||||||
public class Wraith extends FlyingUnit{
|
public class Wraith extends FlyingUnit{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.anuke.mindustry.game;
|
package io.anuke.mindustry.game;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
@@ -195,7 +195,8 @@ public class EventType{
|
|||||||
public static class BlockBuildEndEvent{
|
public static class BlockBuildEndEvent{
|
||||||
public final Tile tile;
|
public final Tile tile;
|
||||||
public final Team team;
|
public final Team team;
|
||||||
public final @Nullable Player player;
|
public final @Nullable
|
||||||
|
Player player;
|
||||||
public final boolean breaking;
|
public final boolean breaking;
|
||||||
|
|
||||||
public BlockBuildEndEvent(Tile tile, @Nullable Player player, Team team, boolean breaking){
|
public BlockBuildEndEvent(Tile tile, @Nullable Player player, Team team, boolean breaking){
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package io.anuke.mindustry.game;
|
package io.anuke.mindustry.game;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.audio.*;
|
import io.anuke.arc.audio.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
@@ -22,7 +22,8 @@ public class MusicControl{
|
|||||||
public Array<Music> darkMusic = Array.with();
|
public Array<Music> darkMusic = Array.with();
|
||||||
private Music lastRandomPlayed;
|
private Music lastRandomPlayed;
|
||||||
private Interval timer = new Interval();
|
private Interval timer = new Interval();
|
||||||
private @Nullable Music current;
|
private @Nullable
|
||||||
|
Music current;
|
||||||
private float fade;
|
private float fade;
|
||||||
private boolean silenced;
|
private boolean silenced;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package io.anuke.mindustry.graphics;
|
package io.anuke.mindustry.graphics;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.graphics.glutils.Shader;
|
import io.anuke.arc.graphics.glutils.Shader;
|
||||||
import io.anuke.arc.scene.ui.layout.Scl;
|
import io.anuke.arc.scene.ui.layout.Scl;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.Time;
|
import io.anuke.arc.util.Time;
|
||||||
|
|
||||||
public class Shaders{
|
public class Shaders{
|
||||||
public static Shadow shadow;
|
public static Shadow shadow;
|
||||||
public static BlockBuild blockbuild;
|
public static BlockBuild blockbuild;
|
||||||
public static @Nullable Shield shield;
|
public static @Nullable
|
||||||
|
Shield shield;
|
||||||
public static UnitBuild build;
|
public static UnitBuild build;
|
||||||
public static FogShader fog;
|
public static FogShader fog;
|
||||||
public static MenuShader menu;
|
public static MenuShader menu;
|
||||||
|
|||||||
193
core/src/io/anuke/mindustry/mod/ContentParser.java
Normal file
193
core/src/io/anuke/mindustry/mod/ContentParser.java
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
package io.anuke.mindustry.mod;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.graphics.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.arc.util.reflect.*;
|
||||||
|
import io.anuke.arc.util.serialization.*;
|
||||||
|
import io.anuke.arc.util.serialization.Json.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.entities.bullet.*;
|
||||||
|
import io.anuke.mindustry.entities.type.*;
|
||||||
|
import io.anuke.mindustry.game.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.world.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class ContentParser{
|
||||||
|
private static final boolean ignoreUnknownFields = true;
|
||||||
|
private ObjectMap<Class<?>, ContentType> contentTypes = new ObjectMap<>();
|
||||||
|
|
||||||
|
private Json parser = new Json(){
|
||||||
|
public <T> T readValue(Class<T> type, Class elementType, JsonValue jsonData){
|
||||||
|
try{
|
||||||
|
if(type == BulletType.class){
|
||||||
|
BulletType b = (BulletType)Bullets.class.getField(jsonData.asString()).get(null);
|
||||||
|
if(b == null) throw new IllegalArgumentException("Bullet type not found: " + jsonData.asString());
|
||||||
|
return (T)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type != null && Content.class.isAssignableFrom(type)){
|
||||||
|
return (T)Vars.content.getByName(contentTypes.getThrow(type, () -> new IllegalArgumentException("No content type for class: " + type.getSimpleName())), jsonData.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.readValue(type, elementType, jsonData);
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ObjectMap<ContentType, TypeParser<?>> parsers = ObjectMap.of(
|
||||||
|
ContentType.block, (TypeParser<Block>)(mod, name, value) -> {
|
||||||
|
String clas = value.getString("type");
|
||||||
|
Class<Block> type = resolve("io.anuke.mindustry.world." + clas, "io.anuke.mindustry.world.blocks." + clas, "io.anuke.mindustry.world.blocks.defense" + clas);
|
||||||
|
Block block = type.getDeclaredConstructor(String.class).newInstance(mod + "-" + name);
|
||||||
|
value.remove("type");
|
||||||
|
readFields(block, value);
|
||||||
|
|
||||||
|
//make block visible
|
||||||
|
if(block.buildRequirements != null){
|
||||||
|
block.buildVisibility = () -> true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
},
|
||||||
|
ContentType.item, (TypeParser<Item>)(mod, name, value) -> {
|
||||||
|
Item item = new Item(mod + "-" + name, new Color(Color.black));
|
||||||
|
readFields(item, value);
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
ContentType.unit, (TypeParser<UnitType>)(mod, name, value) -> {
|
||||||
|
String clas = value.getString("type");
|
||||||
|
Class<BaseUnit> type = resolve("io.anuke.mindustry.entities.type.base." + clas);
|
||||||
|
java.lang.reflect.Constructor<BaseUnit> cons = type.getDeclaredConstructor();
|
||||||
|
UnitType unit = new UnitType(mod + "-" + name, type, () -> {
|
||||||
|
try{
|
||||||
|
return cons.newInstance();
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
value.remove("type");
|
||||||
|
readFields(unit, value);
|
||||||
|
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private void init(){
|
||||||
|
for(ContentType type : ContentType.all){
|
||||||
|
Array<Content> arr = Vars.content.getBy(type);
|
||||||
|
if(!arr.isEmpty()){
|
||||||
|
Class<?> c = arr.first().getClass();
|
||||||
|
//get base content class, skipping intermediates
|
||||||
|
while(!(c.getSuperclass() == Content.class || c.getSuperclass() == UnlockableContent.class || c.getSuperclass() == UnlockableContent.class)){
|
||||||
|
c = c.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
contentTypes.put(c, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses content from a json file.
|
||||||
|
* @param name the name of the file without its extension
|
||||||
|
* @param json the json to parse
|
||||||
|
* @param type the type of content this is
|
||||||
|
* @return the content that was parsed
|
||||||
|
*/
|
||||||
|
public Content parse(String mod, String name, String json, ContentType type) throws Exception{
|
||||||
|
if(contentTypes.isEmpty()){
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonValue value = parser.fromJson(null, json);
|
||||||
|
if(!parsers.containsKey(type)){
|
||||||
|
throw new SerializationException("No parsers for content type '" + type + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
Content c = parsers.get(type).parse(mod, name, value);
|
||||||
|
checkNulls(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks all @NonNull fields in this object, recursively.
|
||||||
|
* Throws an exception if any are null.*/
|
||||||
|
private void checkNulls(Object object){
|
||||||
|
checkNulls(object, new ObjectSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNulls(Object object, ObjectSet<Object> checked){
|
||||||
|
checked.add(object);
|
||||||
|
|
||||||
|
parser.getFields(object.getClass()).each((name, field) -> {
|
||||||
|
try{
|
||||||
|
if(field.field.getType().isPrimitive()) return;
|
||||||
|
|
||||||
|
Object obj = field.field.get(object);
|
||||||
|
if(field.field.isAnnotationPresent(NonNull.class) && field.field.get(object) == null){
|
||||||
|
throw new RuntimeException("Field '" + name + "' in " + object.getClass().getSimpleName() + " is missing!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(obj != null && !checked.contains(obj)){
|
||||||
|
checkNulls(obj, checked);
|
||||||
|
checked.add(obj);
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readFields(Object object, JsonValue jsonMap){
|
||||||
|
Class type = object.getClass();
|
||||||
|
ObjectMap<String, FieldMetadata> fields = parser.getFields(type);
|
||||||
|
for(JsonValue child = jsonMap.child; child != null; child = child.next){
|
||||||
|
FieldMetadata metadata = fields.get(child.name().replace(" ", "_"));
|
||||||
|
if(metadata == null){
|
||||||
|
if(ignoreUnknownFields){
|
||||||
|
Log.err("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object);
|
||||||
|
continue;
|
||||||
|
}else{
|
||||||
|
SerializationException ex = new SerializationException("Field not found: " + child.name + " (" + type.getName() + ")");
|
||||||
|
ex.addTrace(child.trace());
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Field field = metadata.field;
|
||||||
|
try{
|
||||||
|
field.set(object, parser.readValue(field.getType(), metadata.elementType, child));
|
||||||
|
}catch(ReflectionException ex){
|
||||||
|
throw new SerializationException("Error accessing field: " + field.getName() + " (" + type.getName() + ")", ex);
|
||||||
|
}catch(SerializationException ex){
|
||||||
|
ex.addTrace(field.getName() + " (" + type.getName() + ")");
|
||||||
|
throw ex;
|
||||||
|
}catch(RuntimeException runtimeEx){
|
||||||
|
SerializationException ex = new SerializationException(runtimeEx);
|
||||||
|
ex.addTrace(child.trace());
|
||||||
|
ex.addTrace(field.getName() + " (" + type.getName() + ")");
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tries to resolve a class from a list of potential class names. */
|
||||||
|
private <T> Class<T> resolve(String... potentials) throws Exception{
|
||||||
|
for(String type : potentials){
|
||||||
|
try{
|
||||||
|
return (Class<T>)Class.forName(type);
|
||||||
|
}catch(Exception ignored){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Type not found: " + potentials[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TypeParser<T extends Content>{
|
||||||
|
T parse(String mod, String name, JsonValue value) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
core/src/io/anuke/mindustry/mod/Mod.java
Normal file
30
core/src/io/anuke/mindustry/mod/Mod.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package io.anuke.mindustry.mod;
|
||||||
|
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
|
|
||||||
|
public class Mod{
|
||||||
|
/** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/
|
||||||
|
public FileHandle getConfig(){
|
||||||
|
return Vars.mods.getConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called after all plugins have been created and commands have been registered.*/
|
||||||
|
public void init(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create any content needed here. */
|
||||||
|
public void loadContent(){}
|
||||||
|
|
||||||
|
/** Register any commands to be used on the server side, e.g. from the console. */
|
||||||
|
public void registerServerCommands(CommandHandler handler){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Register any commands to be used on the client side, e.g. sent from an in-game player.. */
|
||||||
|
public void registerClientCommands(CommandHandler handler){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
284
core/src/io/anuke/mindustry/mod/Mods.java
Normal file
284
core/src/io/anuke/mindustry/mod/Mods.java
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
package io.anuke.mindustry.mod;
|
||||||
|
|
||||||
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.assets.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
|
import io.anuke.arc.graphics.*;
|
||||||
|
import io.anuke.arc.graphics.Pixmap.*;
|
||||||
|
import io.anuke.arc.graphics.Texture.*;
|
||||||
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.arc.util.io.*;
|
||||||
|
import io.anuke.arc.util.serialization.*;
|
||||||
|
import io.anuke.mindustry.game.*;
|
||||||
|
import io.anuke.mindustry.type.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class Mods implements Loadable{
|
||||||
|
private Json json = new Json();
|
||||||
|
private ContentParser parser = new ContentParser();
|
||||||
|
private ObjectMap<String, Array<FileHandle>> bundles = new ObjectMap<>();
|
||||||
|
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites");
|
||||||
|
|
||||||
|
private int totalSprites;
|
||||||
|
private PixmapPacker packer;
|
||||||
|
|
||||||
|
private Array<LoadedMod> loaded = new Array<>();
|
||||||
|
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
|
||||||
|
private boolean requiresRestart;
|
||||||
|
|
||||||
|
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
||||||
|
* Call this in init(). */
|
||||||
|
public FileHandle getConfig(Mod mod){
|
||||||
|
ModMeta load = metas.get(mod.getClass());
|
||||||
|
if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!");
|
||||||
|
return modDirectory.child(load.name).child("config.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the loaded mod found by class, or null if not found. */
|
||||||
|
public @Nullable
|
||||||
|
LoadedMod getMod(Class<? extends Mod> type){
|
||||||
|
return loaded.find(l -> l.mod.getClass() == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Imports an external mod file.*/
|
||||||
|
public void importMod(FileHandle file) throws IOException{
|
||||||
|
FileHandle dest = modDirectory.child(file.name());
|
||||||
|
if(dest.exists()){
|
||||||
|
throw new IOException("A mod with the same filename already exists!");
|
||||||
|
}
|
||||||
|
|
||||||
|
file.copyTo(dest);
|
||||||
|
try{
|
||||||
|
loaded.add(loadMod(file));
|
||||||
|
requiresRestart = true;
|
||||||
|
}catch(IOException e){
|
||||||
|
dest.delete();
|
||||||
|
throw e;
|
||||||
|
}catch(Throwable t){
|
||||||
|
dest.delete();
|
||||||
|
throw new IOException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Repacks all in-game sprites. */
|
||||||
|
@Override
|
||||||
|
public void loadAsync(){
|
||||||
|
if(loaded.isEmpty()) return;
|
||||||
|
|
||||||
|
packer = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true);
|
||||||
|
for(LoadedMod mod : loaded){
|
||||||
|
try{
|
||||||
|
int packed = 0;
|
||||||
|
for(FileHandle file : mod.root.child("sprites").list()){
|
||||||
|
if(file.extension().equals("png")){
|
||||||
|
try(InputStream stream = file.read()){
|
||||||
|
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||||
|
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||||
|
packer.pack(mod.name + "-" + file.nameWithoutExtension(), pixmap);
|
||||||
|
pixmap.dispose();
|
||||||
|
packed ++;
|
||||||
|
totalSprites ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.info("Packed {0} images for mod '{1}'.", packed, mod.meta.name);
|
||||||
|
}catch(IOException e){
|
||||||
|
Log.err("Error packing images for mod: {0}", mod.meta.name);
|
||||||
|
e.printStackTrace();
|
||||||
|
if(!headless) ui.showException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadSync(){
|
||||||
|
if(packer == null) return;
|
||||||
|
|
||||||
|
if(totalSprites > 0){
|
||||||
|
TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest;
|
||||||
|
packer.getPages().each(page -> page.updateTexture(filter, filter, false));
|
||||||
|
packer.getPages().each(page -> page.getRects().each((name, rect) -> Core.atlas.addRegion(name, page.getTexture(), (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height)));
|
||||||
|
}
|
||||||
|
|
||||||
|
packer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a mod file and marks it for requiring a restart. */
|
||||||
|
public void removeMod(LoadedMod mod){
|
||||||
|
if(mod.file.isDirectory()){
|
||||||
|
mod.file.deleteDirectory();
|
||||||
|
}else{
|
||||||
|
mod.file.delete();
|
||||||
|
}
|
||||||
|
loaded.remove(mod);
|
||||||
|
requiresRestart = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean requiresRestart(){
|
||||||
|
return requiresRestart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads all mods from the folder, but does call any methods on them.*/
|
||||||
|
public void load(){
|
||||||
|
for(FileHandle file : modDirectory.list()){
|
||||||
|
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && file.child("mod.json").exists())) continue;
|
||||||
|
|
||||||
|
try{
|
||||||
|
loaded.add(loadMod(file));
|
||||||
|
}catch(IllegalArgumentException ignored){
|
||||||
|
}catch(Exception e){
|
||||||
|
Log.err("Failed to load plugin file {0}. Skipping.", file);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildFiles(){
|
||||||
|
for(LoadedMod mod : loaded){
|
||||||
|
for(FileHandle file : mod.root.list()){
|
||||||
|
//ignore special folders like bundles or sprites
|
||||||
|
if(file.isDirectory() && !specialFolders.contains(file.name())){
|
||||||
|
//TODO calling child/parent on these files will give you gibberish; create wrapper class.
|
||||||
|
file.walk(f -> filet.addFile(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//load up bundles.
|
||||||
|
FileHandle folder = mod.root.child("bundles");
|
||||||
|
if(folder.exists()){
|
||||||
|
for(FileHandle file : folder.list()){
|
||||||
|
if(file.name().startsWith("bundle") && file.extension().equals("properties")){
|
||||||
|
String name = file.nameWithoutExtension();
|
||||||
|
bundles.getOr(name, Array::new).add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add new keys to each bundle
|
||||||
|
I18NBundle bundle = Core.bundle;
|
||||||
|
while(bundle != null){
|
||||||
|
String str = bundle.getLocale().toString();
|
||||||
|
String locale = "bundle" + (str.isEmpty() ? "" : "_" + str);
|
||||||
|
for(FileHandle file : bundles.getOr(locale, Array::new)){
|
||||||
|
try{
|
||||||
|
PropertiesUtils.load(bundle.getProperties(), file.reader());
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bundle = bundle.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates all the content found in mod files. */
|
||||||
|
public void loadContent(){
|
||||||
|
for(LoadedMod mod : loaded){
|
||||||
|
if(mod.root.child("content").exists()){
|
||||||
|
FileHandle contentRoot = mod.root.child("content");
|
||||||
|
for(ContentType type : ContentType.all){
|
||||||
|
FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s");
|
||||||
|
if(folder.exists()){
|
||||||
|
for(FileHandle file : folder.list()){
|
||||||
|
if(file.extension().equals("json")){
|
||||||
|
try{
|
||||||
|
Content loaded = parser.parse(mod.name, file.nameWithoutExtension(), file.readString(), type);
|
||||||
|
Log.info("[{0}] Loaded '{1}'.", mod.meta.name, loaded);
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException("Failed to parse content file '" + file + "' for mod '" + mod.meta.name + "'.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
each(Mod::loadContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return all loaded mods. */
|
||||||
|
public Array<LoadedMod> all(){
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates through each mod with a main class.*/
|
||||||
|
public void each(Consumer<Mod> cons){
|
||||||
|
loaded.each(p -> p.mod != null, p -> cons.accept(p.mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads a mod file+meta, but does not add it to the list.
|
||||||
|
* Note that directories can be loaded as mods.*/
|
||||||
|
private LoadedMod loadMod(FileHandle sourceFile) throws Exception{
|
||||||
|
FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile);
|
||||||
|
|
||||||
|
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("plugin.json");
|
||||||
|
if(!metaf.exists()){
|
||||||
|
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json' file, skipping.", sourceFile);
|
||||||
|
throw new IllegalArgumentException("No mod.json found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ModMeta meta = json.fromJson(ModMeta.class, metaf.readString());
|
||||||
|
String camelized = meta.name.replace(" ", "");
|
||||||
|
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
|
||||||
|
Mod mainMod;
|
||||||
|
|
||||||
|
//make sure the main class exists before loading it; if it doesn't just don't put it there
|
||||||
|
if(zip.child(mainClass.replace('.', '/') + ".class").exists()){
|
||||||
|
//other platforms don't have standard java class loaders
|
||||||
|
if(mobile){
|
||||||
|
throw new IllegalArgumentException("This mod is not compatible with " + (ios ? "iOS" : "Android") + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
URLClassLoader classLoader = new URLClassLoader(new URL[]{sourceFile.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||||
|
Class<?> main = classLoader.loadClass(mainClass);
|
||||||
|
metas.put(main, meta);
|
||||||
|
mainMod = (Mod)main.getDeclaredConstructor().newInstance();
|
||||||
|
}else{
|
||||||
|
mainMod = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LoadedMod(sourceFile, zip, mainMod, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents a plugin that has been loaded from a jar file.*/
|
||||||
|
public static class LoadedMod{
|
||||||
|
/** The location of this mod's zip file/folder on the disk. */
|
||||||
|
public final FileHandle file;
|
||||||
|
/** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */
|
||||||
|
public final FileHandle root;
|
||||||
|
/** The mod's main class; may be null. */
|
||||||
|
public final @Nullable Mod mod;
|
||||||
|
/** Internal mod name. Used for textures. */
|
||||||
|
public final String name;
|
||||||
|
/** This mod's metadata. */
|
||||||
|
public final ModMeta meta;
|
||||||
|
|
||||||
|
//TODO implement
|
||||||
|
protected boolean enabled;
|
||||||
|
|
||||||
|
public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){
|
||||||
|
this.root = root;
|
||||||
|
this.file = file;
|
||||||
|
this.mod = mod;
|
||||||
|
this.meta = meta;
|
||||||
|
this.name = meta.name.toLowerCase().replace(" ", "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Plugin metadata information.*/
|
||||||
|
public static class ModMeta{
|
||||||
|
public String name, author, description, version, main;
|
||||||
|
public String[] dependencies = {}; //TODO implement
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ public class CrashSender{
|
|||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
|
|
||||||
//don't create crash logs for custom builds, as it's expected
|
//don't create crash logs for custom builds, as it's expected
|
||||||
if(Version.build == -1) return;
|
if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))) return;
|
||||||
|
|
||||||
//attempt to load version regardless
|
//attempt to load version regardless
|
||||||
if(Version.number == 0){
|
if(Version.number == 0){
|
||||||
@@ -143,8 +143,7 @@ public class CrashSender{
|
|||||||
private static void ex(Runnable r){
|
private static void ex(Runnable r){
|
||||||
try{
|
try{
|
||||||
r.run();
|
r.run();
|
||||||
}catch(Throwable t){
|
}catch(Throwable ignored){
|
||||||
t.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.pooling.*;
|
import io.anuke.arc.util.pooling.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
@@ -21,7 +21,8 @@ public class Net{
|
|||||||
private boolean server;
|
private boolean server;
|
||||||
private boolean active;
|
private boolean active;
|
||||||
private boolean clientLoaded;
|
private boolean clientLoaded;
|
||||||
private @Nullable StreamBuilder currentStream;
|
private @Nullable
|
||||||
|
StreamBuilder currentStream;
|
||||||
|
|
||||||
private final Array<Object> packetQueue = new Array<>();
|
private final Array<Object> packetQueue = new Array<>();
|
||||||
private final ObjectMap<Class<?>, Consumer> clientListeners = new ObjectMap<>();
|
private final ObjectMap<Class<?>, Consumer> clientListeners = new ObjectMap<>();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.net.Administration.*;
|
import io.anuke.mindustry.net.Administration.*;
|
||||||
@@ -15,7 +15,8 @@ import static io.anuke.mindustry.Vars.netServer;
|
|||||||
public abstract class NetConnection{
|
public abstract class NetConnection{
|
||||||
public final String address;
|
public final String address;
|
||||||
public boolean mobile, modclient;
|
public boolean mobile, modclient;
|
||||||
public @Nullable Player player;
|
public @Nullable
|
||||||
|
Player player;
|
||||||
|
|
||||||
/** ID of last recieved client snapshot. */
|
/** ID of last recieved client snapshot. */
|
||||||
public int lastRecievedClientSnapshot = -1;
|
public int lastRecievedClientSnapshot = -1;
|
||||||
|
|||||||
@@ -1,28 +1,9 @@
|
|||||||
package io.anuke.mindustry.plugin;
|
package io.anuke.mindustry.plugin;
|
||||||
|
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.mindustry.mod.*;
|
||||||
import io.anuke.arc.util.*;
|
|
||||||
import io.anuke.mindustry.*;
|
|
||||||
|
|
||||||
public abstract class Plugin{
|
/** Use Mod instead. */
|
||||||
|
@Deprecated
|
||||||
/** @return the config file for this plugin, as the file 'plugins/[plugin-name]/config.json'.*/
|
public abstract class Plugin extends Mod{
|
||||||
public FileHandle getConfig(){
|
|
||||||
return Vars.plugins.getConfig(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called after all plugins have been created and commands have been registered.*/
|
|
||||||
public void init(){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Register any commands to be used on the server side, e.g. from the console. */
|
|
||||||
public void registerServerCommands(CommandHandler handler){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Register any commands to be used on the client side, e.g. sent from an in-game player.. */
|
|
||||||
public void registerClientCommands(CommandHandler handler){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
package io.anuke.mindustry.plugin;
|
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.collection.*;
|
|
||||||
import io.anuke.arc.files.*;
|
|
||||||
import io.anuke.arc.function.*;
|
|
||||||
import io.anuke.arc.util.*;
|
|
||||||
import io.anuke.mindustry.io.*;
|
|
||||||
|
|
||||||
import java.net.*;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.pluginDirectory;
|
|
||||||
|
|
||||||
public class Plugins{
|
|
||||||
private Array<LoadedPlugin> loaded = new Array<>();
|
|
||||||
private ObjectMap<Class<?>, PluginMeta> metas = new ObjectMap<>();
|
|
||||||
|
|
||||||
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
|
||||||
* Call this in init(). */
|
|
||||||
public FileHandle getConfig(Plugin plugin){
|
|
||||||
PluginMeta load = metas.get(plugin.getClass());
|
|
||||||
if(load == null) throw new IllegalArgumentException("Plugin is not loaded yet (or missing)!");
|
|
||||||
return pluginDirectory.child(load.name).child("config.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the loaded plugin found by class, or null if not found. */
|
|
||||||
public @Nullable LoadedPlugin getPlugin(Class<? extends Plugin> type){
|
|
||||||
return loaded.find(l -> l.plugin.getClass() == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Loads all plugins from the folder, but does call any methods on them.*/
|
|
||||||
public void load(){
|
|
||||||
for(FileHandle file : pluginDirectory.list()){
|
|
||||||
if(!file.extension().equals("jar")) continue;
|
|
||||||
|
|
||||||
try{
|
|
||||||
loaded.add(loadPlugin(file));
|
|
||||||
}catch(IllegalArgumentException ignored){
|
|
||||||
}catch(Exception e){
|
|
||||||
Log.err("Failed to load plugin file {0}. Skipping.", file);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return all loaded plugins. */
|
|
||||||
public Array<LoadedPlugin> all(){
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Iterates through each plugin.*/
|
|
||||||
public void each(Consumer<Plugin> cons){
|
|
||||||
loaded.each(p -> cons.accept(p.plugin));
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoadedPlugin loadPlugin(FileHandle jar) throws Exception{
|
|
||||||
FileHandle zip = new ZipFileHandle(jar);
|
|
||||||
|
|
||||||
FileHandle metaf = zip.child("plugin.json");
|
|
||||||
if(!metaf.exists()){
|
|
||||||
Log.warn("Plugin {0} doesn't have a 'plugin.json' file, skipping.", jar);
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginMeta meta = JsonIO.read(PluginMeta.class, metaf.readString());
|
|
||||||
|
|
||||||
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
|
||||||
Class<?> main = classLoader.loadClass(meta.main);
|
|
||||||
metas.put(main, meta);
|
|
||||||
return new LoadedPlugin(jar, zip, (Plugin)main.getDeclaredConstructor().newInstance(), meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Represents a plugin that has been loaded from a jar file.*/
|
|
||||||
public static class LoadedPlugin{
|
|
||||||
public final FileHandle jarFile;
|
|
||||||
public final FileHandle zipRoot;
|
|
||||||
public final Plugin plugin;
|
|
||||||
public final PluginMeta meta;
|
|
||||||
|
|
||||||
public LoadedPlugin(FileHandle jarFile, FileHandle zipRoot, Plugin plugin, PluginMeta meta){
|
|
||||||
this.zipRoot = zipRoot;
|
|
||||||
this.jarFile = jarFile;
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.meta = meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Plugin metadata information.*/
|
|
||||||
public static class PluginMeta{
|
|
||||||
public String name, author, main, description;
|
|
||||||
public String version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,5 +13,7 @@ public enum ContentType{
|
|||||||
effect,
|
effect,
|
||||||
zone,
|
zone,
|
||||||
loadout,
|
loadout,
|
||||||
typeid
|
typeid;
|
||||||
|
|
||||||
|
public static final ContentType[] all = values();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.collection.*;
|
|||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
@@ -13,8 +14,9 @@ import io.anuke.mindustry.gen.*;
|
|||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
public class UnitType extends UnlockableContent{
|
public class UnitType extends UnlockableContent{
|
||||||
public final TypeID typeID;
|
public final @NonNull
|
||||||
public final Supplier<? extends BaseUnit> constructor;
|
TypeID typeID;
|
||||||
|
public final @NonNull Supplier<? extends BaseUnit> constructor;
|
||||||
|
|
||||||
public float health = 60;
|
public float health = 60;
|
||||||
public float hitsize = 7f;
|
public float hitsize = 7f;
|
||||||
@@ -25,7 +27,7 @@ public class UnitType extends UnlockableContent{
|
|||||||
public float baseRotateSpeed = 0.1f;
|
public float baseRotateSpeed = 0.1f;
|
||||||
public float shootCone = 15f;
|
public float shootCone = 15f;
|
||||||
public float mass = 1f;
|
public float mass = 1f;
|
||||||
public boolean isFlying;
|
public boolean flying;
|
||||||
public boolean targetAir = true;
|
public boolean targetAir = true;
|
||||||
public boolean rotateWeapon = false;
|
public boolean rotateWeapon = false;
|
||||||
public float drag = 0.1f;
|
public float drag = 0.1f;
|
||||||
@@ -34,7 +36,7 @@ public class UnitType extends UnlockableContent{
|
|||||||
public int itemCapacity = 30;
|
public int itemCapacity = 30;
|
||||||
public ObjectSet<Item> toMine = ObjectSet.with(Items.lead, Items.copper);
|
public ObjectSet<Item> toMine = ObjectSet.with(Items.lead, Items.copper);
|
||||||
public float buildPower = 0.3f, minePower = 0.7f;
|
public float buildPower = 0.3f, minePower = 0.7f;
|
||||||
public Weapon weapon;
|
public @NonNull Weapon weapon;
|
||||||
public float weaponOffsetY, engineOffset = 6f, engineSize = 2f;
|
public float weaponOffsetY, engineOffset = 6f, engineSize = 2f;
|
||||||
public ObjectSet<StatusEffect> immunities = new ObjectSet<>();
|
public ObjectSet<StatusEffect> immunities = new ObjectSet<>();
|
||||||
public Sound deathSound = Sounds.bang;
|
public Sound deathSound = Sounds.bang;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.audio.*;
|
|||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
@@ -25,7 +26,7 @@ public class Weapon{
|
|||||||
protected static float minPlayerDist = 20f;
|
protected static float minPlayerDist = 20f;
|
||||||
protected static int sequenceNum = 0;
|
protected static int sequenceNum = 0;
|
||||||
/** bullet shot */
|
/** bullet shot */
|
||||||
public BulletType bullet;
|
public @NonNull BulletType bullet;
|
||||||
/** shell ejection effect */
|
/** shell ejection effect */
|
||||||
public Effect ejectEffect = Fx.none;
|
public Effect ejectEffect = Fx.none;
|
||||||
/** weapon reload in frames */
|
/** weapon reload in frames */
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package io.anuke.mindustry.ui.dialogs;
|
package io.anuke.mindustry.ui.dialogs;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.scene.ui.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
@@ -15,7 +15,8 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
public class MapPlayDialog extends FloatingDialog{
|
public class MapPlayDialog extends FloatingDialog{
|
||||||
CustomRulesDialog dialog = new CustomRulesDialog();
|
CustomRulesDialog dialog = new CustomRulesDialog();
|
||||||
Rules rules;
|
Rules rules;
|
||||||
@NonNull Gamemode selectedGamemode = Gamemode.survival;
|
@NonNull
|
||||||
|
Gamemode selectedGamemode = Gamemode.survival;
|
||||||
Map lastMap;
|
Map lastMap;
|
||||||
|
|
||||||
public MapPlayDialog(){
|
public MapPlayDialog(){
|
||||||
|
|||||||
88
core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java
Normal file
88
core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package io.anuke.mindustry.ui.dialogs;
|
||||||
|
|
||||||
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.mindustry.gen.*;
|
||||||
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class ModsDialog extends FloatingDialog{
|
||||||
|
|
||||||
|
public ModsDialog(){
|
||||||
|
super("$mods");
|
||||||
|
addCloseButton();
|
||||||
|
shown(this::setup);
|
||||||
|
|
||||||
|
hidden(() -> {
|
||||||
|
if(mods.requiresRestart()){
|
||||||
|
ui.showOkText("$mods", "$mod.requiresrestart", () -> {
|
||||||
|
Core.app.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
shown(() -> Core.app.post(() -> {
|
||||||
|
Core.settings.getBoolOnce("modsalpha", () -> {
|
||||||
|
ui.showText("$mods", "$mods.alphainfo");
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
cont.clear();
|
||||||
|
cont.defaults().width(520f).pad(4);
|
||||||
|
if(!mods.all().isEmpty()){
|
||||||
|
cont.pane(table -> {
|
||||||
|
table.margin(10f).top();
|
||||||
|
for(LoadedMod mod : mods.all()){
|
||||||
|
table.table(Styles.black6, t -> {
|
||||||
|
t.defaults().pad(2).left().top();
|
||||||
|
t.margin(14f).left();
|
||||||
|
t.table(title -> {
|
||||||
|
title.left();
|
||||||
|
title.add("[accent]" + mod.meta.name + "[lightgray] v" + mod.meta.version);
|
||||||
|
title.add().growX();
|
||||||
|
|
||||||
|
title.addImageButton(Icon.trash16Small, Styles.cleari, () -> ui.showConfirm("$confirm", "$mod.remove.confirm", () -> {
|
||||||
|
mods.removeMod(mod);
|
||||||
|
setup();
|
||||||
|
})).size(50f);
|
||||||
|
}).growX().left().padTop(-14f).padRight(-14f);
|
||||||
|
|
||||||
|
t.row();
|
||||||
|
if(mod.meta.author != null){
|
||||||
|
t.add(Core.bundle.format("mod.author", mod.meta.author));
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
|
if(mod.meta.description != null){
|
||||||
|
t.labelWrap("[lightgray]" + mod.meta.description).growX();
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
}).width(500f);
|
||||||
|
table.row();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}else{
|
||||||
|
cont.table(Styles.black6, t -> t.add("$mods.none")).height(80f);
|
||||||
|
}
|
||||||
|
|
||||||
|
cont.row();
|
||||||
|
|
||||||
|
cont.addImageTextButton("$mod.import", Icon.add, () -> {
|
||||||
|
platform.showFileChooser(true, "zip", file -> {
|
||||||
|
try{
|
||||||
|
mods.importMod(file);
|
||||||
|
setup();
|
||||||
|
}catch(IOException e){
|
||||||
|
ui.showException(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).margin(12f).width(500f);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.*;
|
|||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
|
import io.anuke.arc.input.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.scene.*;
|
import io.anuke.arc.scene.*;
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ public class MenuFragment extends Fragment{
|
|||||||
),
|
),
|
||||||
new Buttoni("$editor", Icon.editorSmall, ui.maps::show),
|
new Buttoni("$editor", Icon.editorSmall, ui.maps::show),
|
||||||
steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
|
steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
|
||||||
|
new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show),
|
||||||
new Buttoni("$settings", Icon.toolsSmall, ui.settings::show),
|
new Buttoni("$settings", Icon.toolsSmall, ui.settings::show),
|
||||||
new Buttoni("$about.button", Icon.infoSmall, ui.about::show),
|
new Buttoni("$about.button", Icon.infoSmall, ui.about::show),
|
||||||
new Buttoni("$quit", Icon.exitSmall, Core.app::exit)
|
new Buttoni("$quit", Icon.exitSmall, Core.app::exit)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.anuke.arc.Graphics.Cursor.SystemCursor;
|
|||||||
import io.anuke.arc.graphics.g2d.Draw;
|
import io.anuke.arc.graphics.g2d.Draw;
|
||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.Fx;
|
import io.anuke.mindustry.content.Fx;
|
||||||
import io.anuke.mindustry.entities.Effects;
|
import io.anuke.mindustry.entities.Effects;
|
||||||
import io.anuke.mindustry.entities.effect.RubbleDecal;
|
import io.anuke.mindustry.entities.effect.RubbleDecal;
|
||||||
@@ -172,7 +173,8 @@ public class BuildBlock extends Block{
|
|||||||
* The recipe of the block that is being constructed.
|
* The recipe of the block that is being constructed.
|
||||||
* If there is no recipe for this block, as is the case with rocks, 'previous' is used.
|
* If there is no recipe for this block, as is the case with rocks, 'previous' is used.
|
||||||
*/
|
*/
|
||||||
public @Nullable Block cblock;
|
public @Nullable
|
||||||
|
Block cblock;
|
||||||
|
|
||||||
public float progress = 0;
|
public float progress = 0;
|
||||||
public float buildCost;
|
public float buildCost;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.anuke.mindustry.world.blocks.storage;
|
package io.anuke.mindustry.world.blocks.storage;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.entities.type.TileEntity;
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
@@ -75,6 +75,7 @@ public abstract class StorageBlock extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class StorageBlockEntity extends TileEntity{
|
public class StorageBlockEntity extends TileEntity{
|
||||||
protected @Nullable Tile linkedCore;
|
protected @Nullable
|
||||||
|
Tile linkedCore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
109
fastlane/metadata/steam/ukrainian/achievements.vdf
Normal file
109
fastlane/metadata/steam/ukrainian/achievements.vdf
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
"lang"
|
||||||
|
{
|
||||||
|
"Language" "ukrainian"
|
||||||
|
"Tokens"
|
||||||
|
{
|
||||||
|
"NEW_ACHIEVEMENT_20_0_NAME" "Перевірено"
|
||||||
|
"NEW_ACHIEVEMENT_20_0_DESC" "Завершіть навчання."
|
||||||
|
"NEW_ACHIEVEMENT_20_1_NAME" "Забіяка"
|
||||||
|
"NEW_ACHIEVEMENT_20_1_DESC" "Знищьте 1000 ворожих одиниць."
|
||||||
|
"NEW_ACHIEVEMENT_20_2_NAME" "Чистка"
|
||||||
|
"NEW_ACHIEVEMENT_20_2_DESC" "Знишьте 100 000 ворожих одиниць."
|
||||||
|
"NEW_ACHIEVEMENT_20_3_NAME" "Атмосферне перевезення"
|
||||||
|
"NEW_ACHIEVEMENT_20_3_DESC" "Запустіть 10 000 предметів загалом."
|
||||||
|
"NEW_ACHIEVEMENT_20_5_NAME" "Нескінченні поставки"
|
||||||
|
"NEW_ACHIEVEMENT_20_5_DESC" "Запустіть 1000 000 предметів загалом."
|
||||||
|
"NEW_ACHIEVEMENT_20_6_NAME" "Завойовник"
|
||||||
|
"NEW_ACHIEVEMENT_20_6_DESC" "Виграйте 10 матчів у режимі атаки."
|
||||||
|
"NEW_ACHIEVEMENT_20_7_NAME" "Чемпіон"
|
||||||
|
"NEW_ACHIEVEMENT_20_7_DESC" "Виграйте 10 матчів у режимі PvP."
|
||||||
|
"NEW_ACHIEVEMENT_20_8_NAME" "Бліц"
|
||||||
|
"NEW_ACHIEVEMENT_20_8_DESC" "Знищіть вороже ядро в зоні атаки за 5 хвиль або менше."
|
||||||
|
"NEW_ACHIEVEMENT_20_9_NAME" "Ядерний дощ"
|
||||||
|
"NEW_ACHIEVEMENT_20_9_DESC" "Запустіть своє ядро в зону 30 разів."
|
||||||
|
"NEW_ACHIEVEMENT_20_10_NAME" "Наполегливий"
|
||||||
|
"NEW_ACHIEVEMENT_20_10_DESC" "Виживіть 100 хвиль."
|
||||||
|
"NEW_ACHIEVEMENT_20_11_NAME" "Неперевершений"
|
||||||
|
"NEW_ACHIEVEMENT_20_11_DESC" "Виживіть 500 хвиль."
|
||||||
|
"NEW_ACHIEVEMENT_20_12_NAME" "Дослідник"
|
||||||
|
"NEW_ACHIEVEMENT_20_12_DESC" "Дослідіть все."
|
||||||
|
"NEW_ACHIEVEMENT_20_13_NAME" "Перевертень"
|
||||||
|
"NEW_ACHIEVEMENT_20_13_DESC" "Розблокуйте та перетворіться на кожного меха у грі."
|
||||||
|
"NEW_ACHIEVEMENT_20_14_NAME" "Перевантаження"
|
||||||
|
"NEW_ACHIEVEMENT_20_14_DESC" "Нанесіть шкоду мокрому ворогу електрикою."
|
||||||
|
"NEW_ACHIEVEMENT_20_15_NAME" "Рикошет"
|
||||||
|
"NEW_ACHIEVEMENT_20_15_DESC" "Знищіть ворога його же власною відбитою кулею."
|
||||||
|
"NEW_ACHIEVEMENT_20_17_NAME" "ВЕЛИЧЕЗНА ПОМИЛКА"
|
||||||
|
"NEW_ACHIEVEMENT_20_17_DESC" "Дослідіть маршрутизатора."
|
||||||
|
"NEW_ACHIEVEMENT_20_18_NAME" "Створення"
|
||||||
|
"NEW_ACHIEVEMENT_20_18_DESC" "Побудуйте 10 000 блоків."
|
||||||
|
"NEW_ACHIEVEMENT_20_19_NAME" "Зрівняти з землею"
|
||||||
|
"NEW_ACHIEVEMENT_20_19_DESC" "Знищьте 1000 ворожих блоків."
|
||||||
|
"NEW_ACHIEVEMENT_20_20_NAME" "Ефектна катастрофа"
|
||||||
|
"NEW_ACHIEVEMENT_20_20_DESC" "Торієвий реактор повинен перегрітися й вибихнути."
|
||||||
|
"NEW_ACHIEVEMENT_20_21_NAME" "Картограф"
|
||||||
|
"NEW_ACHIEVEMENT_20_21_DESC" "Зробіть 10 мап."
|
||||||
|
"NEW_ACHIEVEMENT_20_22_NAME" "Веб-переглядач"
|
||||||
|
"NEW_ACHIEVEMENT_20_22_DESC" "Завантажте карту з Майстерні."
|
||||||
|
"NEW_ACHIEVEMENT_20_23_NAME" "Творець"
|
||||||
|
"NEW_ACHIEVEMENT_20_23_DESC" "Опублікуйте карту в Майстерні."
|
||||||
|
"NEW_ACHIEVEMENT_20_24_NAME" "Убивця"
|
||||||
|
"NEW_ACHIEVEMENT_20_24_DESC" "Переможіть боса."
|
||||||
|
"NEW_ACHIEVEMENT_20_25_NAME" "Дослідник"
|
||||||
|
"NEW_ACHIEVEMENT_20_25_DESC" "Розблокуйте всі зони в кампанії."
|
||||||
|
"NEW_ACHIEVEMENT_20_26_NAME" "Завершувач"
|
||||||
|
"NEW_ACHIEVEMENT_20_26_DESC" "Досягніть необхідної хвилі для розблокування конфігурації у всіх зонах."
|
||||||
|
"NEW_ACHIEVEMENT_20_29_NAME" "Матеріал II"
|
||||||
|
"NEW_ACHIEVEMENT_20_29_DESC" "Розблокуйте торій."
|
||||||
|
"NEW_ACHIEVEMENT_20_31_NAME" "Матеріал I"
|
||||||
|
"NEW_ACHIEVEMENT_20_31_DESC" "Розблокуйте титан."
|
||||||
|
"NEW_ACHIEVEMENT_21_0_NAME" "Камікадзе"
|
||||||
|
"NEW_ACHIEVEMENT_21_0_DESC" "Заповніть свого меха вибуховими матеріалами і помріть, створивши вибух."
|
||||||
|
"NEW_ACHIEVEMENT_21_1_NAME" "Це починається"
|
||||||
|
"NEW_ACHIEVEMENT_21_1_DESC" "Побудуйте завод мехів «Кинджал»."
|
||||||
|
"NEW_ACHIEVEMENT_21_2_NAME" "Прямий наступ"
|
||||||
|
"NEW_ACHIEVEMENT_21_2_DESC" "Видайте команду «Атакувати» за допомогою командного центру."
|
||||||
|
"NEW_ACHIEVEMENT_21_3_NAME" "Рій"
|
||||||
|
"NEW_ACHIEVEMENT_21_3_DESC" "100 бойових одиниць повинні бути активними одночасно."
|
||||||
|
"NEW_ACHIEVEMENT_21_4_NAME" "Зграя"
|
||||||
|
"NEW_ACHIEVEMENT_21_4_DESC" "10 фантомних дронів повинні бути активними одночасно."
|
||||||
|
"NEW_ACHIEVEMENT_21_5_NAME" "Летуча армія"
|
||||||
|
"NEW_ACHIEVEMENT_21_5_DESC" "50 Камікадзе повинні бути активними одночасно."
|
||||||
|
"NEW_ACHIEVEMENT_21_6_NAME" "Легіони"
|
||||||
|
"NEW_ACHIEVEMENT_21_6_DESC" "Побудуйте 1000 одиниць загалом."
|
||||||
|
"NEW_ACHIEVEMENT_21_7_NAME" "Супер"
|
||||||
|
"NEW_ACHIEVEMENT_21_7_DESC" "Досягніть рангу S на будь-якій зоні."
|
||||||
|
"NEW_ACHIEVEMENT_21_8_NAME" "А ти молодець"
|
||||||
|
"NEW_ACHIEVEMENT_21_8_DESC" "Досягніть рангу SS на будь-якій зоні."
|
||||||
|
"NEW_ACHIEVEMENT_21_9_NAME" "Ти не послухався"
|
||||||
|
"NEW_ACHIEVEMENT_21_9_DESC" "Помріть у зоні анігіляції."
|
||||||
|
"NEW_ACHIEVEMENT_21_10_NAME" "Просто натисни Shift"
|
||||||
|
"NEW_ACHIEVEMENT_21_10_DESC" "Потоніть, якось."
|
||||||
|
"NEW_ACHIEVEMENT_21_11_NAME" "Збирач"
|
||||||
|
"NEW_ACHIEVEMENT_21_11_DESC" "Наповніть ядро повністю кожним типом матеріалу."
|
||||||
|
"NEW_ACHIEVEMENT_21_12_NAME" "Натовп"
|
||||||
|
"NEW_ACHIEVEMENT_21_12_DESC" "Створіть сервер, на якому буде 10 гравців одночасно."
|
||||||
|
"NEW_ACHIEVEMENT_21_13_NAME" "Невразливий"
|
||||||
|
"NEW_ACHIEVEMENT_21_13_DESC" "Побудуйте Катастрофу і Випалювач."
|
||||||
|
"NEW_ACHIEVEMENT_21_14_NAME" "Зліт"
|
||||||
|
"NEW_ACHIEVEMENT_21_14_DESC" "Запустіть."
|
||||||
|
"NEW_ACHIEVEMENT_21_15_NAME" "Компенсація"
|
||||||
|
"NEW_ACHIEVEMENT_21_15_DESC" "Двічі пропустіть запуск і допустіть знищення ядра ворогом."
|
||||||
|
"NEW_ACHIEVEMENT_21_16_NAME" "Єресь"
|
||||||
|
"NEW_ACHIEVEMENT_21_16_DESC" "Побудуйте два маршрутизатори поруч."
|
||||||
|
"NEW_ACHIEVEMENT_21_17_NAME" "Одинокий захисник"
|
||||||
|
"NEW_ACHIEVEMENT_21_17_DESC" "Виживіть 10 хвиль в першій-ліпшій зоні без будування будування будь-яких блоків."
|
||||||
|
"NEW_ACHIEVEMENT_21_18_NAME" "Спалити"
|
||||||
|
"NEW_ACHIEVEMENT_21_18_DESC" "Використайте піротит в будь-якій башті."
|
||||||
|
"NEW_ACHIEVEMENT_21_19_NAME" "Ефективність"
|
||||||
|
"NEW_ACHIEVEMENT_21_19_DESC" "Охолодіть башту водою чи кріогенною рідиною."
|
||||||
|
"NEW_ACHIEVEMENT_21_20_NAME" "Класичний режим"
|
||||||
|
"NEW_ACHIEVEMENT_21_20_DESC" "Увімкніть пікселізацію."
|
||||||
|
"NEW_ACHIEVEMENT_21_21_NAME" "Науковець"
|
||||||
|
"NEW_ACHIEVEMENT_21_21_DESC" "Відкрийти Wiki з гри."
|
||||||
|
"NEW_ACHIEVEMENT_21_22_NAME" "Впевнений початок"
|
||||||
|
"NEW_ACHIEVEMENT_21_22_DESC" "Вивантажіть в зону 10 000 або більше предметів."
|
||||||
|
"NEW_ACHIEVEMENT_21_23_NAME" "Запалювання"
|
||||||
|
"NEW_ACHIEVEMENT_21_23_DESC" "Підвищте потужність імпульсного реактора."
|
||||||
|
}
|
||||||
|
}
|
||||||
60
fastlane/metadata/steam/ukrainian/description.txt
Normal file
60
fastlane/metadata/steam/ukrainian/description.txt
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
Створюйте складні логістичні мережі для перенесення боєприпасів у башти, видобувайте ресурси для будівництва, і захищайте своє ядро від різних хвиль ворогів. Грайте з друзями на різних платформах у кооперативні ігри, або киньте їм виклик у командних PvP-матчах.
|
||||||
|
|
||||||
|
[img]{STEAM_APP_IMAGE}/extras/ezgif-4-0e70c282f775.gif[/img]
|
||||||
|
|
||||||
|
[h2]Ігровий процес[/h2]
|
||||||
|
|
||||||
|
[list]
|
||||||
|
[*] Створіть бури і конвеєри для переміщення ресурсів в ядро.
|
||||||
|
[*] Використовуйте виробничі блоки для створення передових матеріалів.
|
||||||
|
[*] Створюйте дронів для автоматичного видобутку ресурсів, допомоги в будівництві.
|
||||||
|
[*] Доставляйте рідини й боріться з осередками вогню.
|
||||||
|
[*] Збільшуйте виробництво, постачаючи необов’язкові теплоносії та мастила до ваших оборонно-виробничих блоків.
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Кампанія[/h2]
|
||||||
|
|
||||||
|
[list]
|
||||||
|
[*] Просуньтесь через 12 вбудованих зон з випадковим розташуванням точок появи ворогів.
|
||||||
|
[*] Збирайте і запускайте ресурси.
|
||||||
|
[*] Дослідження нових блоків для сприяння прогресу.
|
||||||
|
[*] Налаштовуйте початкові ресурси для кожної зони
|
||||||
|
[*] Різноманітність цілей та завдань місій.
|
||||||
|
[*] Запросіть своїх друзів для спільного виконання місій.
|
||||||
|
[*] Понад 120 технологічних блоків для освоєння.
|
||||||
|
[*] 19 різних типів дронів, мехів і кораблів.
|
||||||
|
[*] Понад 50 досягнень для завершення.
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2][h2]Ігрові режими[/h2][/h2]
|
||||||
|
|
||||||
|
[*] [b]Виживання[/b]: створіть башти для захисту від ворогів в ігровому процесі, заснованому на захисті башт. Виживайте якомога довше, за бажанням можна запустит своє ядро, щоб використовувати зібрані ресурси для досліджень. Підготуйте свою базу для періодичних атак повітряних босів.
|
||||||
|
[*] [b]Атака[/b]: будуйте заводи бойових одиниць для знищення ворожих ядер, одночасно захищаючи свою базу від хвиль ворожих одиниць.
|
||||||
|
[*] [b]PvP[/b]: змагайтеся з іншими гравцями, щоб знищити ядра один одного. Створюйте бойові одиниці або нападайте на інші бази безпосередньо зі своїми мехами. Створіть різноманітні типи підтримувальиних та наступальних підрозділів, щоб допоможуть вам у досягненні цілей.
|
||||||
|
[*] [b]Пісочниця[/b]: грайте з нескінченними ресурсами без загрози з боку ворога. Використовуйте специфічні для пісочниці елементи та блоки рідких джерел для тестування конструкцій та появи ворогів за запитом.
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Користувацькі ігри & багатоплатформовий мультиплеєр[/h2]
|
||||||
|
|
||||||
|
[list]
|
||||||
|
[*] 12 вбудованих мап на додаток кампанії.
|
||||||
|
[*] Грайте в кооперативі, PvP чи пісочниці.
|
||||||
|
[*] Приєднуйтесь до загальнодоступного сервера, або запросіть друзів на свій приватний сеанс.
|
||||||
|
[*] Користувацькі налаштування гри — ціна блоків, сила ворогів, кількість початкових ресурсів, інтервал між хвилями, тощо.
|
||||||
|
[*] Змішуйте і поєднуйте ігрові режими — комбінуйте PvP і PvE режими разом.
|
||||||
|
[/list]
|
||||||
|
|
||||||
|
[h2]Користувацький редактор мап[/h2]
|
||||||
|
|
||||||
|
[list]
|
||||||
|
[*] Створюйте ландшафт за допомогою візуального редактора.
|
||||||
|
[*] Змінюйте і переглядайте споруди так само як в грі.
|
||||||
|
[*] Регульовані режими інструментів — змініть функціонування кожного інструменту.
|
||||||
|
[*] Потужна система генерації мап, що має безліч різних типів фільтрів для процедурного маніпулювання місцевістю.
|
||||||
|
[*] Застосуйте на своїх мапах шум, спотворення, згладжування, ерозію, симетрію, генерацію руди та випадкову генерацію місцевості.
|
||||||
|
[*] Відкрита гра в жанрі «захист башт» з акцентом на керуванні ресурсами.
|
||||||
|
[*] Розкладки хвиль для мап можна налаштувати.
|
||||||
|
[*] Поширюйте експортовані мапи в Майстерні Steam.
|
||||||
|
[*] Правила для мап можна налаштувати.
|
||||||
|
[*] Використовуйте понад 75 видів блоків навколишнього середовища.
|
||||||
|
[/list]
|
||||||
1
fastlane/metadata/steam/ukrainian/short-description.txt
Normal file
1
fastlane/metadata/steam/ukrainian/short-description.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Нескінченна гра у жанрі «захист вежі» з акцентом на керуванні ресурсами.
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=d4519a9721927165850bfe3135ef6b095c990474
|
archash=678237e0fd2a2e0c26de1ea562960d1effe5ab97
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package io.anuke.mindustry.server;
|
package io.anuke.mindustry.server;
|
||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.util.*;
|
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
|
import io.anuke.mindustry.mod.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -28,5 +28,9 @@ public class MindustryServer implements ApplicationListener{
|
|||||||
Core.app.addListener(logic = new Logic());
|
Core.app.addListener(logic = new Logic());
|
||||||
Core.app.addListener(netServer = new NetServer());
|
Core.app.addListener(netServer = new NetServer());
|
||||||
Core.app.addListener(new ServerControl(args));
|
Core.app.addListener(new ServerControl(args));
|
||||||
|
|
||||||
|
mods.each(Mod::init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ import io.anuke.mindustry.gen.*;
|
|||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
import io.anuke.mindustry.net.Administration.*;
|
import io.anuke.mindustry.net.Administration.*;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
import io.anuke.mindustry.plugin.*;
|
|
||||||
import io.anuke.mindustry.plugin.Plugins.*;
|
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -51,8 +50,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
private PrintWriter socketOutput;
|
private PrintWriter socketOutput;
|
||||||
|
|
||||||
public ServerControl(String[] args){
|
public ServerControl(String[] args){
|
||||||
plugins = new Plugins();
|
|
||||||
|
|
||||||
Core.settings.defaults(
|
Core.settings.defaults(
|
||||||
"shufflemode", "normal",
|
"shufflemode", "normal",
|
||||||
"bans", "",
|
"bans", "",
|
||||||
@@ -110,9 +107,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
Effects.setScreenShakeProvider((a, b) -> {});
|
Effects.setScreenShakeProvider((a, b) -> {});
|
||||||
Effects.setEffectProvider((a, b, c, d, e, f) -> {});
|
Effects.setEffectProvider((a, b, c, d, e, f) -> {});
|
||||||
|
|
||||||
//load plugins
|
|
||||||
plugins.load();
|
|
||||||
|
|
||||||
registerCommands();
|
registerCommands();
|
||||||
|
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
@@ -134,7 +128,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
});
|
});
|
||||||
|
|
||||||
customMapDirectory.mkdirs();
|
customMapDirectory.mkdirs();
|
||||||
pluginDirectory.mkdirs();
|
|
||||||
|
|
||||||
Thread thread = new Thread(this::readCommands, "Server Controls");
|
Thread thread = new Thread(this::readCommands, "Server Controls");
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
@@ -179,11 +172,8 @@ public class ServerControl implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//initialize plugins
|
if(!mods.all().isEmpty()){
|
||||||
plugins.each(io.anuke.mindustry.plugin.Plugin::init);
|
info("&lc{0} mods loaded.", mods.all().size);
|
||||||
|
|
||||||
if(!plugins.all().isEmpty()){
|
|
||||||
info("&lc{0} plugins loaded.", plugins.all().size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
||||||
@@ -326,28 +316,28 @@ public class ServerControl implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.register("plugins", "Display all loaded plugins.", arg -> {
|
handler.register("mods", "Display all loaded mods.", arg -> {
|
||||||
if(!plugins.all().isEmpty()){
|
if(!mods.all().isEmpty()){
|
||||||
info("Plugins:");
|
info("Mods:");
|
||||||
for(LoadedPlugin plugin : plugins.all()){
|
for(LoadedMod mod : mods.all()){
|
||||||
info(" &ly{0} &lcv{1}", plugin.meta.name, plugin.meta.version);
|
info(" &ly{0} &lcv{1}", mod.meta.name, mod.meta.version);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
info("No plugins found.");
|
info("No mods found.");
|
||||||
}
|
}
|
||||||
info("&lyPlugin directory: &lb&fi{0}", pluginDirectory.file().getAbsoluteFile().toString());
|
info("&lyMod directory: &lb&fi{0}", modDirectory.file().getAbsoluteFile().toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.register("plugin", "<name...>", "Display information about a loaded plugin.", arg -> {
|
handler.register("mod", "<name...>", "Display information about a loaded plugin.", arg -> {
|
||||||
LoadedPlugin plugin = plugins.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
|
LoadedMod mod = mods.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
|
||||||
if(plugin != null){
|
if(mod != null){
|
||||||
info("Name: &ly{0}", plugin.meta.name);
|
info("Name: &ly{0}", mod.meta.name);
|
||||||
info("Version: &ly{0}", plugin.meta.version);
|
info("Version: &ly{0}", mod.meta.version);
|
||||||
info("Author: &ly{0}", plugin.meta.author);
|
info("Author: &ly{0}", mod.meta.author);
|
||||||
info("Path: &ly{0}", plugin.jarFile.path());
|
info("Path: &ly{0}", mod.file.path());
|
||||||
info("Description: &ly{0}", plugin.meta.description);
|
info("Description: &ly{0}", mod.meta.description);
|
||||||
}else{
|
}else{
|
||||||
info("No plugin with name &ly'{0}'&lg found.");
|
info("No mod with name &ly'{0}'&lg found.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -759,8 +749,9 @@ public class ServerControl implements ApplicationListener{
|
|||||||
info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post);
|
info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post);
|
||||||
});
|
});
|
||||||
|
|
||||||
plugins.each(p -> p.registerServerCommands(handler));
|
mods.each(p -> p.registerServerCommands(handler));
|
||||||
plugins.each(p -> p.registerClientCommands(netServer.clientCommands));
|
//TODO
|
||||||
|
//plugins.each(p -> p.registerClientCommands(netServer.clientCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readCommands(){
|
private void readCommands(){
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ public class Generators{
|
|||||||
});
|
});
|
||||||
|
|
||||||
ImagePacker.generate("unit-icons", () -> {
|
ImagePacker.generate("unit-icons", () -> {
|
||||||
content.<UnitType>getBy(ContentType.unit).each(type -> !type.isFlying, type -> {
|
content.<UnitType>getBy(ContentType.unit).each(type -> !type.flying, type -> {
|
||||||
type.load();
|
type.load();
|
||||||
type.weapon.load();
|
type.weapon.load();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user