mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-02 03:00:29 +03:00
Merge branch 'master' of https://github.com/Anuken/Mindustry into v9
# Conflicts: # gradle.properties
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
name: Bug report
|
||||
description: The type of device you were playing on
|
||||
description: An issue with the game.
|
||||
labels: ["bug"]
|
||||
|
||||
body:
|
||||
|
||||
@@ -62,7 +62,7 @@ export.file = Экспортировать файл
|
||||
import.file = Импортировать файл
|
||||
copy.clipboard = Скопировать в буфер обмена
|
||||
load.clipboard = Вставить из буфера обмена
|
||||
workshop.browse = Мастерская
|
||||
workshop.browse = Искать в Мастерской
|
||||
workshop.share = Поделиться в Мастерской
|
||||
|
||||
schematic = Схема
|
||||
@@ -74,7 +74,7 @@ schematic.exists = Схема с таким названием уже сущес
|
||||
schematic.import = Импортировать схему...
|
||||
schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Отразить схему
|
||||
schematic.saved = Схема сохранена.
|
||||
schematic.delete.confirm = Эта схема будет поджарена Испепелителем.
|
||||
schematic.delete.confirm = Эта схема будет разнесена в металлолом.
|
||||
schematic.edit = Редактировать схему
|
||||
schematic.info = {0}x{1}, {2} блоков
|
||||
schematic.disabled = [scarlet]Схемы отключены[]\nНа этой [accent]карте[] или [accent]сервере[] запрещено использование схем.
|
||||
@@ -183,7 +183,7 @@ mod.incompletedependencies.details = Этот мод не может быть з
|
||||
mod.requiresversion = Требуется версия игры: [red]{0}
|
||||
|
||||
mod.errors = Ошибки были вызваны загружаемым содержимым.
|
||||
mod.errors.map = [scarlet]Errors have occurred loading map content. All custom content has been disabled.[]\nThis map will likely not function correctly.
|
||||
mod.errors.map = [scarlet]При загрузке ресурсов карты произошли ошибки. Весь пользовательский контент был отключен.[]\nЭта карта, вероятно, не будет работать правильно.
|
||||
mod.noerrorplay = [scarlet]У Вас есть модификации с ошибками.[] Выключите проблемные модификации или исправьте ошибки перед игрой.
|
||||
mod.enable = Вкл.
|
||||
mod.requiresrestart = Теперь игра закроется, чтобы применить изменения в модификациях.
|
||||
@@ -281,7 +281,7 @@ servers.remote = Удалённые серверы
|
||||
servers.global = Серверы сообщества
|
||||
|
||||
servers.disclaimer = Серверы сообщества [accent]не[] принадлежат разработчику и [accent]не[] контролируются им.\n\nСерверы могут содержать пользовательский контент, который не подходит для всех возрастов.
|
||||
servers.connect.confirm = Join the following server?\n\n[accent]{0}[]\n\nOnly connect to servers you trust!
|
||||
servers.connect.confirm = Присоединиться к этому серверу?\n\n[accent]{0}[]\n\nНе подключайтесь к серверам, которым не доверяете!
|
||||
servers.showhidden = Отображать скрытые серверы
|
||||
server.shown = Отображается
|
||||
server.hidden = Скрыт
|
||||
@@ -333,7 +333,7 @@ disconnect.timeout = Время ожидания истекло.
|
||||
disconnect.data = Ошибка при загрузке данных мира!
|
||||
disconnect.snapshottimeout = Превышено время ожидания при получении UDP-снапшотов.\nЭто может быть вызвано нестабильной сетью или соединением.
|
||||
cantconnect = Не удаётся присоединиться к игре ([accent]{0}[]).
|
||||
disconnect.reason = Disconnected: {0}
|
||||
disconnect.reason = Отключение: {0}
|
||||
connecting = [accent]Подключение...
|
||||
reconnecting = [accent]Переподключение...
|
||||
|
||||
@@ -443,7 +443,7 @@ commandmode.nounits = [нет единиц]
|
||||
wave = [accent]Волна {0}
|
||||
wave.cap = [accent]Волна {0}/{1}
|
||||
wave.waiting = [lightgray]Волна через {0}
|
||||
wave.waveInProgress = [lightgray]Волна продолжается
|
||||
wave.waveInProgress = [lightgray]Волна в процессе
|
||||
waiting = [lightgray]Ожидание...
|
||||
waiting.players = Ожидание игроков...
|
||||
wave.enemies = [lightgray]Враги: {0}
|
||||
@@ -1122,7 +1122,7 @@ settings.clearplanetcampaignsaves.confirm = Вы уверены, что хоти
|
||||
paused = [accent]< Пауза >
|
||||
clear = Очистить
|
||||
banned = [scarlet]Запрещено
|
||||
block.limit = [scarlet]Limit: {0} Buildings
|
||||
block.limit = [scarlet]Лимит: {0} блоков
|
||||
unsupported.environment = [scarlet]Неподдерживаемые условия
|
||||
yes = Да
|
||||
no = Нет
|
||||
@@ -2841,8 +2841,8 @@ lglobal.@clientUnit = Боевая единица клиента, выполня
|
||||
lglobal.@clientName = Имя игрока клиента, выполняющего код
|
||||
lglobal.@clientTeam = ID команды клиента, выполняющего код.
|
||||
lglobal.@clientMobile = True, если код работает на мобильном клиенте, иначе False
|
||||
lglobal.@clientMusicPlaying = True if any music is currently playing
|
||||
lglobal.@clientCurrentMusic = Name of the current track being played, or null
|
||||
lglobal.@clientMusicPlaying = True, если в данный момент играет любая музыка
|
||||
lglobal.@clientCurrentMusic = Название текущей проигрываемой музыки, или null
|
||||
|
||||
lenum.type = Тип постройки/единицы. \nНапример, для маршрутизатора это будет [accent]@router[].\nНе строка.
|
||||
lenum.shoot = Стрельба в определённую позицию.
|
||||
@@ -3040,4 +3040,4 @@ lenum.solarmultiplier = Устанавливает множитель получ
|
||||
lenum.dragmultiplier = Устанавливает множитель скорости торможения боевых единиц.
|
||||
lenum.ban = Устанавливает запрещённые блоки и боевые единицы.
|
||||
lenum.unban = Снимает запрет на ранее запрещённые блоки и боевые единицы.
|
||||
lenum.musicvolume = Global music volume multiplier.\nClamped to [0, 1].
|
||||
lenum.musicvolume = Глобальный множитель громкости музыки.\nСокращается до диапазона [0, 1].
|
||||
|
||||
@@ -195,4 +195,5 @@ Jovinull
|
||||
Alon
|
||||
硫缺铅/PyratiteNoLead
|
||||
Space
|
||||
NeilGreenFly
|
||||
NeilGreenFly
|
||||
Sunky.MP3G
|
||||
|
||||
@@ -691,6 +691,7 @@ public class LExecutor{
|
||||
if(target instanceof Senseable se){
|
||||
if(sense instanceof Content co){
|
||||
to.setnum(se.sense(co));
|
||||
return;
|
||||
}else if(sense instanceof LAccess la){
|
||||
Object objOut = se.senseObject(la);
|
||||
|
||||
@@ -701,6 +702,7 @@ public class LExecutor{
|
||||
//object output
|
||||
to.setobj(objOut);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if(sense == LAccess.size || sense == LAccess.bufferSize){
|
||||
@@ -712,9 +714,10 @@ public class LExecutor{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
to.setobj(null);
|
||||
}
|
||||
|
||||
//unrecognized or unhandled property
|
||||
to.setobj(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,6 +224,10 @@ public abstract class LStatement{
|
||||
}
|
||||
|
||||
protected static void showSelectTable(Button b, Cons2<Table, Runnable> hideCons){
|
||||
showSelectTable(b, hideCons, () -> {});
|
||||
}
|
||||
|
||||
protected static void showSelectTable(Button b, Cons2<Table, Runnable> hideCons, Runnable hideCallback){
|
||||
Table t = new Table(Tex.paneSolid){
|
||||
@Override
|
||||
public float getPrefHeight(){
|
||||
@@ -243,6 +247,7 @@ public abstract class LStatement{
|
||||
Runnable hide = () -> {
|
||||
Core.app.post(hitter::remove);
|
||||
t.actions(Actions.fadeOut(0.3f, Interp.fade), Actions.remove());
|
||||
hideCallback.run();
|
||||
};
|
||||
|
||||
hitter.fillParent = true;
|
||||
@@ -256,6 +261,7 @@ public abstract class LStatement{
|
||||
Core.app.post(() -> {
|
||||
hitter.remove();
|
||||
t.remove();
|
||||
hideCallback.run();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2390,21 +2390,7 @@ public class LStatements{
|
||||
|
||||
table.button(b -> {
|
||||
b.image(Icon.pencilSmall);
|
||||
|
||||
Seq<String> soundNames = new Seq<>();
|
||||
|
||||
for(var entry : Core.assets.getAllEntries(Sound.class, new Seq<>())){
|
||||
if(entry.value != Sounds.none && entry.value.file != null){
|
||||
soundNames.add(Strings.getFileNameWithoutExtension(entry.key));
|
||||
}
|
||||
}
|
||||
soundNames.sort();
|
||||
|
||||
String soundName = id.startsWith("@sfx-") ? id.substring(5) : id;
|
||||
b.clicked(() -> showSelect(b, soundNames.toArray(String.class), soundName, t -> {
|
||||
id = "@sfx-" + t;
|
||||
build(table);
|
||||
}, 3, cell -> cell.size(170, 50)));
|
||||
b.clicked(() -> showSoundSelect(b, table));
|
||||
}, Styles.logict, () -> {}).size(40).color(table.color).left().padLeft(-1);
|
||||
|
||||
row(table);
|
||||
@@ -2441,6 +2427,157 @@ public class LStatements{
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
|
||||
private static @Nullable Sound lastPreview;
|
||||
|
||||
private static class SoundChoice{
|
||||
final String category;
|
||||
final String name;
|
||||
final Sound sound;
|
||||
|
||||
SoundChoice(String category, String name, Sound sound){
|
||||
this.category = category;
|
||||
this.name = name;
|
||||
this.sound = sound;
|
||||
}
|
||||
}
|
||||
|
||||
protected void showSoundSelect(Button button, Table table){
|
||||
Seq<SoundChoice> choices = new Seq<>();
|
||||
ObjectMap<String, Seq<SoundChoice>> categories = new ObjectMap<>();
|
||||
|
||||
for(var entry : Core.assets.getAllEntries(Sound.class, new Seq<>())){
|
||||
Sound sound = entry.value;
|
||||
if(sound == Sounds.none || sound == null || sound.file == null) continue;
|
||||
|
||||
String name = Strings.getFileNameWithoutExtension(entry.key);
|
||||
String category = soundCategory(entry.key);
|
||||
|
||||
SoundChoice choice = new SoundChoice(category, name, sound);
|
||||
choices.add(choice);
|
||||
categories.get(category, Seq::new).add(choice);
|
||||
}
|
||||
|
||||
if(choices.isEmpty()) return;
|
||||
|
||||
choices.sort((a, b) -> {
|
||||
int cmp = a.category.compareTo(b.category);
|
||||
return cmp == 0 ? a.name.compareTo(b.name) : cmp;
|
||||
});
|
||||
|
||||
Seq<String> categoryNames = categories.keys().toSeq().sort();
|
||||
categoryNames.insert(0, "all");
|
||||
|
||||
for(var seq : categories.values()){
|
||||
seq.sortComparing(a -> a.name);
|
||||
}
|
||||
|
||||
String current = id.startsWith("@sfx-") ? id.substring(5) : id;
|
||||
String currentCategory = "all";
|
||||
for(var choice : choices){
|
||||
if(choice.name.equals(current)){
|
||||
currentCategory = choice.category;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final String selectedCurrentCategory = currentCategory;
|
||||
|
||||
showSelectTable(button, (root, hide) -> {
|
||||
root.left().top();
|
||||
|
||||
String[] selectedCategory = {categories.containsKey(selectedCurrentCategory) ? selectedCurrentCategory : "all"};
|
||||
Table soundList = new Table();
|
||||
ButtonGroup<Button> tabGroup = new ButtonGroup<>();
|
||||
|
||||
Runnable rebuild = () -> {
|
||||
soundList.clearChildren();
|
||||
soundList.defaults().left().pad(2f);
|
||||
soundList.top();
|
||||
|
||||
Seq<SoundChoice> visible = new Seq<>();
|
||||
if("all".equals(selectedCategory[0])){
|
||||
visible.addAll(choices);
|
||||
}else{
|
||||
visible.addAll(categories.get(selectedCategory[0], Seq::new));
|
||||
}
|
||||
|
||||
if(visible.isEmpty()){
|
||||
soundList.add("@none.found").pad(8f);
|
||||
return;
|
||||
}
|
||||
|
||||
for(var choice : visible){
|
||||
soundList.table(row -> {
|
||||
row.left().top();
|
||||
row.defaults().left();
|
||||
|
||||
row.button(Icon.play, Styles.cleari, 28f, () -> previewSound(choice.sound))
|
||||
.update(b -> b.getStyle().imageUp = choice.sound != null && choice.sound == lastPreview && choice.sound.countPlaying() > 0 ? Icon.pause : Icon.play)
|
||||
.size(40f).padRight(6f);
|
||||
|
||||
String label = "all".equals(selectedCategory[0]) ? choice.category + "/" + choice.name : choice.name;
|
||||
row.button(label, Styles.logicTogglet, () -> {
|
||||
id = "@sfx-" + choice.name;
|
||||
build(table);
|
||||
hide.run();
|
||||
}).growX().height(40f).left().checked(choice.name.equals(current)).with(t -> {
|
||||
t.getLabelCell().growX().left().labelAlign(Align.left).padLeft(10f);
|
||||
}).padRight(4f);
|
||||
}).growX().height(40f).padBottom(3f).row();
|
||||
}
|
||||
};
|
||||
|
||||
root.table(tabs -> {
|
||||
tabs.left().top();
|
||||
tabs.defaults().size(140f, 34f).left();
|
||||
|
||||
for(String category : categoryNames){
|
||||
tabs.button(Strings.capitalize(category), Styles.logicTogglet, () -> {
|
||||
selectedCategory[0] = category;
|
||||
rebuild.run();
|
||||
//fixes flickering
|
||||
var parent = (Table)root.parent.parent;
|
||||
parent.pack();
|
||||
parent.act(0f);
|
||||
}).checked(selectedCategory[0].equals(category)).group(tabGroup).growX().row();
|
||||
}
|
||||
}).top().left().width(160f);
|
||||
|
||||
root.add(soundList).top().width(Math.min(Core.graphics.getWidth() / Scl.scl(1f) * 0.9f, 450f));
|
||||
|
||||
rebuild.run();
|
||||
}, () -> {
|
||||
if(lastPreview != null){
|
||||
lastPreview.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String soundCategory(String entryName){
|
||||
String normalized = entryName.replace('\\', '/');
|
||||
int end = normalized.lastIndexOf('/');
|
||||
if(end < 0) return "Data Patch";
|
||||
|
||||
int start = normalized.lastIndexOf('/', end - 1);
|
||||
return normalized.substring(start + 1, end);
|
||||
}
|
||||
|
||||
private static void previewSound(Sound sound){
|
||||
if(sound == null || sound == Sounds.none) return;
|
||||
|
||||
if(lastPreview != null && lastPreview.countPlaying() > 0 && lastPreview != Sounds.uiButton){
|
||||
lastPreview.stop();
|
||||
if(lastPreview == sound) return; //double tap = stop
|
||||
}
|
||||
|
||||
lastPreview = sound;
|
||||
//don't play the button sound every time
|
||||
if(sound != Sounds.uiButton) Sounds.uiButton.stop();
|
||||
|
||||
//play sound on the UI bus as the main one is paused
|
||||
sound.play(1, 1, 0, false, true, control.sound.uiBus);
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("playmusic")
|
||||
|
||||
@@ -218,7 +218,10 @@ public class DataPatcher{
|
||||
if(reloadContentWorld) fixContentArrays();
|
||||
}
|
||||
|
||||
for(var set : patches){
|
||||
var patchIt = patches.iterator();
|
||||
while(patchIt.hasNext()){
|
||||
PatchAsset set = patchIt.next();
|
||||
|
||||
set.warnings.clear();
|
||||
set.error = false;
|
||||
|
||||
@@ -234,6 +237,7 @@ public class DataPatcher{
|
||||
if(Vars.headless){
|
||||
String[] planets = req.isArray() ? req.asStringArray() : new String[]{req.asString()};
|
||||
if(!Structs.contains(planets, Vars.state.rules.planet.name)){
|
||||
patchIt.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ public class CrashHandler{
|
||||
+ "Cores: " + OS.cores + "\n"
|
||||
+ (cause == null ? "" : "Likely Cause: " + cause.meta.displayName + " (" + cause.name + " v" + cause.meta.version + ")\n")
|
||||
+ (enabledMods == null ? "<no mod init>" : "Mods: " + (enabledMods.isEmpty() ? "none (vanilla)" : enabledMods.toString(", ", mod -> mod.name + ":" + mod.meta.version))) + "\n"
|
||||
+ (state != null && state.data != null && state.data.getPatches().size > 0 ? "Patches: \n" + state.data.getPatches().toString("\n---\n", p -> p.patch) + "\n" : "")
|
||||
+ "\n\n" + error;
|
||||
+ "\n\n" + error
|
||||
+ (state != null && state.data != null && state.data.getPatches().size > 0 ? "\n\nPatches: \n" + state.data.getPatches().toString("\n---\n", p -> p.patch) + "\n" : "");
|
||||
}
|
||||
|
||||
public static void log(Throwable exception){
|
||||
|
||||
@@ -1469,16 +1469,16 @@ public class UnitType extends UnlockableContent implements Senseable{
|
||||
float scl = xscl;
|
||||
if(unit.inFogTo(Vars.player.team())) return;
|
||||
|
||||
if(buildSpeed > 0f){
|
||||
boolean isPayload = !unit.isAdded();
|
||||
|
||||
if(buildSpeed > 0f && !isPayload){
|
||||
unit.drawBuilding();
|
||||
}
|
||||
|
||||
if(unit.mining()){
|
||||
if(unit.mining() && !isPayload){
|
||||
drawMining(unit);
|
||||
}
|
||||
|
||||
boolean isPayload = !unit.isAdded();
|
||||
|
||||
Mechc mech = unit instanceof Mechc m ? m : null;
|
||||
Segmentc seg = unit instanceof Segmentc c ? c : null;
|
||||
float z =
|
||||
|
||||
Reference in New Issue
Block a user