diff --git a/.gitignore b/.gitignore index 6d6cc255d6..5a3526c397 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /core/assets/mindustry-saves/ /core/assets/mindustry-maps/ +/core/assets/bundles/output/ /deploy/ /desktop/packr-out/ /desktop/packr-export/ diff --git a/.travis.yml b/.travis.yml index 06a66fa107..56ba77b664 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,14 @@ jdk: android: components: - - android-26 + - android-27 # Additional components - extra-google-google_play_services - extra-google-m2repository - extra-android-m2repository - - addon-google_apis-google-26 + - addon-google_apis-google-27 + - build-tools-27.0.3 script: - ./gradlew desktop:dist diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 342222acf8..64fc9d218b 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -20,7 +20,7 @@ diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 774e01ae69..d532734999 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -49,237 +49,237 @@ import java.util.Locale; import static io.anuke.mindustry.Vars.*; public class AndroidLauncher extends AndroidApplication{ - public static final int PERMISSION_REQUEST_CODE = 1; + public static final int PERMISSION_REQUEST_CODE = 1; - boolean doubleScaleTablets = true; - FileChooser chooser; + boolean doubleScaleTablets = true; + FileChooser chooser; - @Override - protected void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); + @Override + protected void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); - AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); - config.useImmersiveMode = true; + AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); + config.useImmersiveMode = true; - Platform.instance = new Platform(){ - DateFormat format = SimpleDateFormat.getDateTimeInstance(); + Platform.instance = new Platform(){ + DateFormat format = SimpleDateFormat.getDateTimeInstance(); - @Override - public boolean hasDiscord() { - return isPackageInstalled("com.discord"); - } + @Override + public boolean hasDiscord(){ + return isPackageInstalled("com.discord"); + } - @Override - public String format(Date date){ - return format.format(date); - } + @Override + public String format(Date date){ + return format.format(date); + } - @Override - public String format(int number){ - return NumberFormat.getIntegerInstance().format(number); - } + @Override + public String format(int number){ + return NumberFormat.getIntegerInstance().format(number); + } - @Override - public void addDialog(TextField field, int length){ - TextFieldDialogListener.add(field, 0, length); - } + @Override + public void addDialog(TextField field, int length){ + TextFieldDialogListener.add(field, 0, length); + } - @Override - public String getLocaleName(Locale locale){ - return locale.getDisplayName(locale); - } + @Override + public String getLocaleName(Locale locale){ + return locale.getDisplayName(locale); + } - @Override - public void openDonations() { - showDonations(); - } + @Override + public void openDonations(){ + showDonations(); + } - @Override - public ThreadProvider getThreadProvider() { - return new DefaultThreadImpl(); - } + @Override + public ThreadProvider getThreadProvider(){ + return new DefaultThreadImpl(); + } - @Override - public boolean isDebug() { - return false; - } + @Override + public boolean isDebug(){ + return false; + } - @Override - public String getUUID() { - try { - String s = Secure.getString(getContext().getContentResolver(), - Secure.ANDROID_ID); + @Override + public String getUUID(){ + try{ + String s = Secure.getString(getContext().getContentResolver(), + Secure.ANDROID_ID); - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) - + Character.digit(s.charAt(i + 1), 16)); - } + int len = s.length(); + byte[] data = new byte[len / 2]; + for(int i = 0; i < len; i += 2){ + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } - String result = new String(Base64Coder.encode(data)); + String result = new String(Base64Coder.encode(data)); - if(result.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID."); + if(result.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID."); - return result; - }catch (Exception e){ - return super.getUUID(); - } - } + return result; + }catch(Exception e){ + return super.getUUID(); + } + } - @Override - public void shareFile(FileHandle file){ + @Override + public void shareFile(FileHandle file){ - } + } - @Override - public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype) { - chooser = new FileChooser(text, file -> file.extension().equalsIgnoreCase(filetype), open, cons); + @Override + public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype){ + chooser = new FileChooser(text, file -> file.extension().equalsIgnoreCase(filetype), open, cons); - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && - checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ - chooser.show(); - chooser = null; - }else { - ArrayList perms = new ArrayList<>(); + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ + chooser.show(); + chooser = null; + }else{ + ArrayList perms = new ArrayList<>(); - if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); - } + if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } - if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); - } + if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } - requestPermissions(perms.toArray(new String[perms.size()]), PERMISSION_REQUEST_CODE); - } - } + requestPermissions(perms.toArray(new String[perms.size()]), PERMISSION_REQUEST_CODE); + } + } - @Override - public void beginForceLandscape() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } + @Override + public void beginForceLandscape(){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } - @Override - public void endForceLandscape() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); - } + @Override + public void endForceLandscape(){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); + } - @Override - public boolean canDonate(){ - return true; - } - }; + @Override + public boolean canDonate(){ + return true; + } + }; - try { - ProviderInstaller.installIfNeeded(this); - } catch (GooglePlayServicesRepairableException e) { - GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); - apiAvailability.getErrorDialog(this, e.getConnectionStatusCode(), 0).show(); - } catch (GooglePlayServicesNotAvailableException e) { - Log.e("SecurityException", "Google Play Services not available."); - } + try{ + ProviderInstaller.installIfNeeded(this); + }catch(GooglePlayServicesRepairableException e){ + GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); + apiAvailability.getErrorDialog(this, e.getConnectionStatusCode(), 0).show(); + }catch(GooglePlayServicesNotAvailableException e){ + Log.e("SecurityException", "Google Play Services not available."); + } - if(doubleScaleTablets && isTablet(this.getContext())){ - Unit.dp.addition = 0.5f; - } - - config.hideStatusBar = true; + if(doubleScaleTablets && isTablet(this.getContext())){ + Unit.dp.addition = 0.5f; + } + + config.hideStatusBar = true; Net.setClientProvider(new KryoClient()); Net.setServerProvider(new KryoServer()); initialize(new Mindustry(), config); - checkFiles(getIntent()); - } + checkFiles(getIntent()); + } - @Override - public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { - if(requestCode == PERMISSION_REQUEST_CODE){ - for(int i : grantResults){ - if(i != PackageManager.PERMISSION_GRANTED) return; - } + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults){ + if(requestCode == PERMISSION_REQUEST_CODE){ + for(int i : grantResults){ + if(i != PackageManager.PERMISSION_GRANTED) return; + } - if(chooser != null){ - chooser.show(); - } - } - } + if(chooser != null){ + chooser.show(); + } + } + } - private void checkFiles(Intent intent){ - try { - Uri uri = intent.getData(); - if (uri != null) { - File myFile = null; - String scheme = uri.getScheme(); - if (scheme.equals("file")) { - String fileName = uri.getEncodedPath(); - myFile = new File(fileName); - } else if (!scheme.equals("content")) { - //error - return; - } + private void checkFiles(Intent intent){ + try{ + Uri uri = intent.getData(); + if(uri != null){ + File myFile = null; + String scheme = uri.getScheme(); + if(scheme.equals("file")){ + String fileName = uri.getEncodedPath(); + myFile = new File(fileName); + }else if(!scheme.equals("content")){ + //error + return; + } - boolean save = uri.getPath().endsWith(saveExtension); - boolean map = uri.getPath().endsWith(mapExtension); + boolean save = uri.getPath().endsWith(saveExtension); + boolean map = uri.getPath().endsWith(mapExtension); - InputStream inStream; - if (myFile != null) inStream = new FileInputStream(myFile); - else inStream = getContentResolver().openInputStream(uri); + InputStream inStream; + if(myFile != null) inStream = new FileInputStream(myFile); + else inStream = getContentResolver().openInputStream(uri); - Gdx.app.postRunnable(() -> { + Gdx.app.postRunnable(() -> { - if(save){ //open save - System.out.println("Opening save."); - FileHandle file = Gdx.files.local("temp-save." + saveExtension); - file.write(inStream, false); + if(save){ //open save + System.out.println("Opening save."); + FileHandle file = Gdx.files.local("temp-save." + saveExtension); + file.write(inStream, false); - if(SaveIO.isSaveValid(file)){ - try{ - SaveSlot slot = control.getSaves().importSave(file); - ui.load.runLoadSave(slot); - }catch (IOException e){ - ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false))); - } - }else{ - ui.showError("$text.save.import.invalid"); - } + if(SaveIO.isSaveValid(file)){ + try{ + SaveSlot slot = control.getSaves().importSave(file); + ui.load.runLoadSave(slot); + }catch(IOException e){ + ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false))); + } + }else{ + ui.showError("$text.save.import.invalid"); + } - }else if(map){ //open map - Gdx.app.postRunnable(() -> { - System.out.println("Opening map."); - if (!ui.editor.isShown()) { - ui.editor.show(); - } + }else if(map){ //open map + Gdx.app.postRunnable(() -> { + System.out.println("Opening map."); + if(!ui.editor.isShown()){ + ui.editor.show(); + } - ui.editor.beginEditMap(inStream); - }); - } - }); - } + ui.editor.beginEditMap(inStream); + }); + } + }); + } - }catch (IOException e){ - e.printStackTrace(); - } - } - - private boolean isPackageInstalled(String packagename) { - try { - getPackageManager().getPackageInfo(packagename, 0); - return true; - } catch (Exception e) { - return false; - } - } - - private boolean isTablet(Context context) { - TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - return manager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE; - } - - private void showDonations(){ - Intent intent = new Intent(this, DonationsActivity.class); - startActivity(intent); - } + }catch(IOException e){ + e.printStackTrace(); + } + } + + private boolean isPackageInstalled(String packagename){ + try{ + getPackageManager().getPackageInfo(packagename, 0); + return true; + }catch(Exception e){ + return false; + } + } + + private boolean isTablet(Context context){ + TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + return manager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE; + } + + private void showDonations(){ + Intent intent = new Intent(this, DonationsActivity.class); + startActivity(intent); + } } diff --git a/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java index 7a530e817a..56a1b92c72 100644 --- a/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java +++ b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java @@ -11,20 +11,20 @@ import android.widget.EditText; import com.badlogic.gdx.Gdx; public class AndroidTextFieldDialog{ - private Activity activity; - private EditText userInput; - private AlertDialog.Builder builder; - private TextPromptListener listener; - private boolean isBuild; + private Activity activity; + private EditText userInput; + private AlertDialog.Builder builder; + private TextPromptListener listener; + private boolean isBuild; - public AndroidTextFieldDialog() { - this.activity = (Activity)Gdx.app; - load(); - } + public AndroidTextFieldDialog(){ + this.activity = (Activity) Gdx.app; + load(); + } - public AndroidTextFieldDialog show() { + public AndroidTextFieldDialog show(){ - activity.runOnUiThread(() -> { + activity.runOnUiThread(() -> { AlertDialog dialog = builder.create(); dialog.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); @@ -33,12 +33,12 @@ public class AndroidTextFieldDialog{ }); - return this; - } + return this; + } - private AndroidTextFieldDialog load() { + private AndroidTextFieldDialog load(){ - activity.runOnUiThread(() -> { + activity.runOnUiThread(() -> { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity); LayoutInflater li = LayoutInflater.from(activity); @@ -55,64 +55,65 @@ public class AndroidTextFieldDialog{ isBuild = true; }); - // Wait till TextPrompt is built. - while (!isBuild) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { } - } + // Wait till TextPrompt is built. + while(!isBuild){ + try{ + Thread.sleep(10); + }catch(InterruptedException e){ + } + } - return this; - } + return this; + } - public int getResourceId(String pVariableName, String pVariableType) { - try { - return activity.getResources().getIdentifier(pVariableName, pVariableType, activity.getPackageName()); - } catch (Exception e) { - Gdx.app.error("Android Dialogs", "Cannot find resouce with name: " + pVariableName - + " Did you copy the layouts to /res/layouts and /res/layouts_v14 ?"); - e.printStackTrace(); - return -1; - } - } + public int getResourceId(String pVariableName, String pVariableType){ + try{ + return activity.getResources().getIdentifier(pVariableName, pVariableType, activity.getPackageName()); + }catch(Exception e){ + Gdx.app.error("Android Dialogs", "Cannot find resouce with name: " + pVariableName + + " Did you copy the layouts to /res/layouts and /res/layouts_v14 ?"); + e.printStackTrace(); + return -1; + } + } - public AndroidTextFieldDialog setText(CharSequence value) { - userInput.append(value); - return this; - } + public AndroidTextFieldDialog setText(CharSequence value){ + userInput.append(value); + return this; + } - public AndroidTextFieldDialog setCancelButtonLabel(CharSequence label) { - builder.setNegativeButton(label, (dialog, id) -> dialog.cancel()); - return this; - } + public AndroidTextFieldDialog setCancelButtonLabel(CharSequence label){ + builder.setNegativeButton(label, (dialog, id) -> dialog.cancel()); + return this; + } - public AndroidTextFieldDialog setConfirmButtonLabel(CharSequence label) { - builder.setPositiveButton(label, (dialog, id) -> { - if (listener != null && !userInput.getText().toString().isEmpty()) { + public AndroidTextFieldDialog setConfirmButtonLabel(CharSequence label){ + builder.setPositiveButton(label, (dialog, id) -> { + if(listener != null && !userInput.getText().toString().isEmpty()){ listener.confirm(userInput.getText().toString()); } }); - return this; - } + return this; + } - public AndroidTextFieldDialog setTextPromptListener(TextPromptListener listener) { - this.listener = listener; - return this; - } + public AndroidTextFieldDialog setTextPromptListener(TextPromptListener listener){ + this.listener = listener; + return this; + } - public AndroidTextFieldDialog setInputType(int type) { - userInput.setInputType(type); - return this; - } + public AndroidTextFieldDialog setInputType(int type){ + userInput.setInputType(type); + return this; + } - public AndroidTextFieldDialog setMaxLength(int length) { - userInput.setFilters(new InputFilter[] { new InputFilter.LengthFilter(length) }); - return this; - } - - public interface TextPromptListener{ - void confirm(String text); - } + public AndroidTextFieldDialog setMaxLength(int length){ + userInput.setFilters(new InputFilter[]{new InputFilter.LengthFilter(length)}); + return this; + } + + public interface TextPromptListener{ + void confirm(String text); + } } diff --git a/android/src/io/anuke/mindustry/DonationsActivity.java b/android/src/io/anuke/mindustry/DonationsActivity.java index 690ccc3413..c6e61c61b2 100644 --- a/android/src/io/anuke/mindustry/DonationsActivity.java +++ b/android/src/io/anuke/mindustry/DonationsActivity.java @@ -8,12 +8,9 @@ import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.Button; - import org.sufficientlysecure.donations.DonationsFragment; -public class DonationsActivity extends FragmentActivity { - DonationsFragment donationsFragment; - +public class DonationsActivity extends FragmentActivity{ /** * Google */ @@ -21,13 +18,14 @@ public class DonationsActivity extends FragmentActivity { private static final String[] GOOGLE_CATALOG = new String[]{ "mindustry.donation.1", "mindustry.donation.2", "mindustry.donation.5", "mindustry.donation.10", "mindustry.donation.15", - "mindustry.donation.25", "mindustry.donation.50" }; + "mindustry.donation.25", "mindustry.donation.50"}; + DonationsFragment donationsFragment; /** * Called when the activity is first created. */ @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setTheme(R.style.GdxTheme); @@ -35,7 +33,7 @@ public class DonationsActivity extends FragmentActivity { setContentView(R.layout.donations_activity); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - if (BuildConfig.DONATIONS_GOOGLE) { + if(BuildConfig.DONATIONS_GOOGLE){ donationsFragment = DonationsFragment.newInstance(BuildConfig.DEBUG, true, GOOGLE_PUBKEY, GOOGLE_CATALOG, getResources().getStringArray(R.array.donation_google_catalog_values), false, null, null, null, false, null, null, false, null); @@ -48,9 +46,10 @@ public class DonationsActivity extends FragmentActivity { public void onStart(){ super.onStart(); - Button b = ((Button)findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button)); - b.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View view) { + Button b = ((Button) findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button)); + b.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view){ donationsFragment.donateGoogleOnClick(donationsFragment.getView()); b.setEnabled(false); } @@ -58,20 +57,19 @@ public class DonationsActivity extends FragmentActivity { } - /** * Needed for Google Play In-app Billing. It uses startIntentSenderForResult(). The result is not propagated to * the Fragment like in startActivityForResult(). Thus we need to propagate manually to our Fragment. */ @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { + protected void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); - Button b = ((Button)findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button)); + Button b = ((Button) findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button)); b.setEnabled(true); FragmentManager fragmentManager = getSupportFragmentManager(); Fragment fragment = fragmentManager.findFragmentByTag("donationsFragment"); - if (fragment != null) { + if(fragment != null){ fragment.onActivityResult(requestCode, resultCode, data); //TODO donation event, set settings? } diff --git a/android/src/io/anuke/mindustry/TextFieldDialogListener.java b/android/src/io/anuke/mindustry/TextFieldDialogListener.java index c6f328d785..be1cc6d924 100644 --- a/android/src/io/anuke/mindustry/TextFieldDialogListener.java +++ b/android/src/io/anuke/mindustry/TextFieldDialogListener.java @@ -11,57 +11,57 @@ import io.anuke.ucore.scene.event.InputListener; import io.anuke.ucore.scene.ui.TextField; public class TextFieldDialogListener extends ClickListener{ - private TextField field; - private int type; - private int max; + private TextField field; + private int type; + private int max; - public static void add(TextField field, int type, int max){ - field.addListener(new TextFieldDialogListener(field, type, max)); - field.addListener(new InputListener(){ - public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - Gdx.input.setOnscreenKeyboardVisible(false); - return false; - } - }); - } + //type - 0 is text, 1 is numbers, 2 is decimals + public TextFieldDialogListener(TextField field, int type, int max){ + this.field = field; + this.type = type; + this.max = max; + } - public static void add(TextField field){ - add(field, 0, 16); - } + public static void add(TextField field, int type, int max){ + field.addListener(new TextFieldDialogListener(field, type, max)); + field.addListener(new InputListener(){ + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){ + Gdx.input.setOnscreenKeyboardVisible(false); + return false; + } + }); + } - //type - 0 is text, 1 is numbers, 2 is decimals - public TextFieldDialogListener(TextField field, int type, int max){ - this.field = field; - this.type = type; - this.max = max; - } + public static void add(TextField field){ + add(field, 0, 16); + } - public void clicked(final InputEvent event, float x, float y){ - - if(Gdx.app.getType() == ApplicationType.Desktop) return; - - AndroidTextFieldDialog dialog = new AndroidTextFieldDialog(); + public void clicked(final InputEvent event, float x, float y){ - dialog.setTextPromptListener(text -> { + if(Gdx.app.getType() == ApplicationType.Desktop) return; + + AndroidTextFieldDialog dialog = new AndroidTextFieldDialog(); + + dialog.setTextPromptListener(text -> { field.clearText(); field.appendText(text); field.fire(new ChangeListener.ChangeEvent()); Gdx.graphics.requestRendering(); }); - if(type == 0){ - dialog.setInputType(InputType.TYPE_CLASS_TEXT); - }else if(type == 1){ - dialog.setInputType(InputType.TYPE_CLASS_NUMBER); - }else if(type == 2){ - dialog.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL); - } + if(type == 0){ + dialog.setInputType(InputType.TYPE_CLASS_TEXT); + }else if(type == 1){ + dialog.setInputType(InputType.TYPE_CLASS_NUMBER); + }else if(type == 2){ + dialog.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL); + } - dialog.setConfirmButtonLabel("OK").setText(field.getText()); - dialog.setCancelButtonLabel("Cancel"); - dialog.setMaxLength(max); - dialog.show(); - event.cancel(); + dialog.setConfirmButtonLabel("OK").setText(field.getText()); + dialog.setCancelButtonLabel("Cancel"); + dialog.setMaxLength(max); + dialog.show(); + event.cancel(); - } + } } diff --git a/annotations/src/io/anuke/annotations/Annotations.java b/annotations/src/io/anuke/annotations/Annotations.java index 325663f951..cc60478fee 100644 --- a/annotations/src/io/anuke/annotations/Annotations.java +++ b/annotations/src/io/anuke/annotations/Annotations.java @@ -9,70 +9,31 @@ import java.lang.annotation.Target; * Goal: To create a system to send events to the server from the client and vice versa, without creating a new packet type each time.
* These events may optionally also trigger on the caller client/server as well.
*/ -public class Annotations { +public class Annotations{ - /**Marks a method as invokable remotely across a server/client connection.*/ - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.CLASS) - public @interface Remote { - /**Specifies the locations from which this method can be invoked.*/ - Loc targets() default Loc.server; - /**Specifies which methods are generated. Only affects server-to-client methods.*/ - Variant variants() default Variant.all; - /**The local locations where this method is called locally, when invoked.*/ - Loc called() default Loc.none; - /**Whether to forward this packet to all other clients upon recieval. Server only.*/ - boolean forward() default false; - /**Whether the packet for this method is sent with UDP instead of TCP. - * UDP is faster, but is prone to packet loss and duplication.*/ - boolean unreliable() default false; - /**The simple class name where this method is placed.*/ - String in() default "Call"; - /**Priority of this event.*/ - PacketPriority priority() default PacketPriority.normal; - } - - /**Specifies that this method will be used to write classes of the type returned by {@link #value()}.
- * This method must return void and have two parameters, the first being of type {@link java.nio.ByteBuffer} and the second - * being the type returned by {@link #value()}.*/ - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.CLASS) - public @interface WriteClass { - Class value(); - } - - /**Specifies that this method will be used to read classes of the type returned by {@link #value()}.
- * This method must return the type returned by {@link #value()}, - * and have one parameter, being of type {@link java.nio.ByteBuffer}.*/ - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.CLASS) - public @interface ReadClass { - Class value(); - } - - public enum PacketPriority { - /**Gets put in a queue and processed if not connected.*/ + public enum PacketPriority{ + /** Gets put in a queue and processed if not connected. */ normal, - /**Gets handled immediately, regardless of connection status.*/ + /** Gets handled immediately, regardless of connection status. */ high, - /**Does not get handled unless client is connected.*/ + /** Does not get handled unless client is connected. */ low } - /**A set of two booleans, one specifying server and one specifying client.*/ - public enum Loc { - /**Method can only be invoked on the client from the server.*/ + /** A set of two booleans, one specifying server and one specifying client. */ + public enum Loc{ + /** Method can only be invoked on the client from the server. */ server(true, false), - /**Method can only be invoked on the server from the client.*/ + /** Method can only be invoked on the server from the client. */ client(false, true), - /**Method can be invoked from anywhere*/ + /** Method can be invoked from anywhere */ both(true, true), - /**Neither server no client.*/ + /** Neither server nor client. */ none(false, false); - /**If true, this method can be invoked ON clients FROM servers.*/ + /** If true, this method can be invoked ON clients FROM servers. */ public final boolean isServer; - /**If true, this method can be invoked ON servers FROM clients.*/ + /** If true, this method can be invoked ON servers FROM clients. */ public final boolean isClient; Loc(boolean server, boolean client){ @@ -81,12 +42,12 @@ public class Annotations { } } - public enum Variant { - /**Method can only be invoked targeting one player.*/ + public enum Variant{ + /** Method can only be invoked targeting one player. */ one(true, false), - /**Method can only be invoked targeting all players.*/ + /** Method can only be invoked targeting all players. */ all(false, true), - /**Method targets both one player and all players.*/ + /** Method targets both one player and all players. */ both(true, true); public final boolean isOne, isAll; @@ -96,4 +57,55 @@ public class Annotations { this.isAll = isAll; } } + + /** Marks a method as invokable remotely across a server/client connection. */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.CLASS) + public @interface Remote{ + /** Specifies the locations from which this method can be invoked. */ + Loc targets() default Loc.server; + + /** Specifies which methods are generated. Only affects server-to-client methods. */ + Variant variants() default Variant.all; + + /** The local locations where this method is called locally, when invoked. */ + Loc called() default Loc.none; + + /** Whether to forward this packet to all other clients upon recieval. Client only. */ + boolean forward() default false; + + /** + * Whether the packet for this method is sent with UDP instead of TCP. + * UDP is faster, but is prone to packet loss and duplication. + */ + boolean unreliable() default false; + + /** The simple class name where this method is placed. */ + String in() default "Call"; + + /** Priority of this event. */ + PacketPriority priority() default PacketPriority.normal; + } + + /** + * Specifies that this method will be used to write classes of the type returned by {@link #value()}.
+ * This method must return void and have two parameters, the first being of type {@link java.nio.ByteBuffer} and the second + * being the type returned by {@link #value()}. + */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.CLASS) + public @interface WriteClass{ + Class value(); + } + + /** + * Specifies that this method will be used to read classes of the type returned by {@link #value()}.
+ * This method must return the type returned by {@link #value()}, + * and have one parameter, being of type {@link java.nio.ByteBuffer}. + */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.CLASS) + public @interface ReadClass{ + Class value(); + } } diff --git a/annotations/src/io/anuke/annotations/ClassEntry.java b/annotations/src/io/anuke/annotations/ClassEntry.java index 3997eb6029..a9be2ec134 100644 --- a/annotations/src/io/anuke/annotations/ClassEntry.java +++ b/annotations/src/io/anuke/annotations/ClassEntry.java @@ -2,14 +2,14 @@ package io.anuke.annotations; import java.util.ArrayList; -/**Represents a class witha list method entries to include in it.*/ -public class ClassEntry { - /**All methods in this generated class.*/ +/** Represents a class witha list method entries to include in it. */ +public class ClassEntry{ + /** All methods in this generated class. */ public final ArrayList methods = new ArrayList<>(); - /**Simple class name.*/ + /** Simple class name. */ public final String name; - public ClassEntry(String name) { + public ClassEntry(String name){ this.name = name; } } diff --git a/annotations/src/io/anuke/annotations/IOFinder.java b/annotations/src/io/anuke/annotations/IOFinder.java index c2dd8e3567..9276b9b887 100644 --- a/annotations/src/io/anuke/annotations/IOFinder.java +++ b/annotations/src/io/anuke/annotations/IOFinder.java @@ -10,12 +10,16 @@ import javax.tools.Diagnostic.Kind; import java.util.HashMap; import java.util.Set; -/**This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass} - * and {@link io.anuke.annotations.Annotations.ReadClass} annotations.*/ -public class IOFinder { +/** + * This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass} + * and {@link io.anuke.annotations.Annotations.ReadClass} annotations. + */ +public class IOFinder{ - /**Finds all class serializers for all types and returns them. Logs errors when necessary. - * Maps fully qualified class names to their serializers.*/ + /** + * Finds all class serializers for all types and returns them. Logs errors when necessary. + * Maps fully qualified class names to their serializers. + */ public HashMap findSerializers(RoundEnvironment env){ HashMap result = new HashMap<>(); @@ -51,33 +55,33 @@ public class IOFinder { } private String getValue(WriteClass write){ - try { + try{ Class type = write.value(); return type.getName(); - }catch (MirroredTypeException e){ + }catch(MirroredTypeException e){ return e.getTypeMirror().toString(); } } private String getValue(ReadClass read){ - try { + try{ Class type = read.value(); return type.getName(); - }catch (MirroredTypeException e){ + }catch(MirroredTypeException e){ return e.getTypeMirror().toString(); } } - /**Information about read/write methods for a specific class type.*/ + /** Information about read/write methods for a specific class type. */ public static class ClassSerializer{ - /**Fully qualified method name of the reader.*/ + /** Fully qualified method name of the reader. */ public final String readMethod; - /**Fully qualified method name of the writer.*/ + /** Fully qualified method name of the writer. */ public final String writeMethod; - /**Fully qualified class type name.*/ + /** Fully qualified class type name. */ public final String classType; - public ClassSerializer(String readMethod, String writeMethod, String classType) { + public ClassSerializer(String readMethod, String writeMethod, String classType){ this.readMethod = readMethod; this.writeMethod = writeMethod; this.classType = classType; diff --git a/annotations/src/io/anuke/annotations/MethodEntry.java b/annotations/src/io/anuke/annotations/MethodEntry.java index ee47fccb4a..3566516372 100644 --- a/annotations/src/io/anuke/annotations/MethodEntry.java +++ b/annotations/src/io/anuke/annotations/MethodEntry.java @@ -6,32 +6,34 @@ import io.anuke.annotations.Annotations.Variant; import javax.lang.model.element.ExecutableElement; -/**Class that repesents a remote method to be constructed and put into a class.*/ -public class MethodEntry { - /**Simple target class name.*/ +/** Class that repesents a remote method to be constructed and put into a class. */ +public class MethodEntry{ + /** Simple target class name. */ public final String className; - /**Fully qualified target method to call.*/ + /** Fully qualified target method to call. */ public final String targetMethod; - /**Whether this method can be called on a client/server.*/ + /** Whether this method can be called on a client/server. */ public final Loc where; - /**Whether an additional 'one' and 'all' method variant is generated. At least one of these must be true. - * Only applicable to client (server-invoked) methods.*/ + /** + * Whether an additional 'one' and 'all' method variant is generated. At least one of these must be true. + * Only applicable to client (server-invoked) methods. + */ public final Variant target; - /**Whether this method is called locally as well as remotely.*/ + /** Whether this method is called locally as well as remotely. */ public final Loc local; - /**Whether this method is unreliable and uses UDP.*/ + /** Whether this method is unreliable and uses UDP. */ public final boolean unreliable; - /**Whether to forward this method call to all other clients when a client invokes it. Server only.*/ + /** Whether to forward this method call to all other clients when a client invokes it. Server only. */ public final boolean forward; - /**Unique method ID.*/ + /** Unique method ID. */ public final int id; - /**The element method associated with this entry.*/ + /** The element method associated with this entry. */ public final ExecutableElement element; - /**The assigned packet priority. Only used in clients.*/ + /** The assigned packet priority. Only used in clients. */ public final PacketPriority priority; public MethodEntry(String className, String targetMethod, Loc where, Variant target, - Loc local, boolean unreliable, boolean forward, int id, ExecutableElement element, PacketPriority priority) { + Loc local, boolean unreliable, boolean forward, int id, ExecutableElement element, PacketPriority priority){ this.className = className; this.forward = forward; this.targetMethod = targetMethod; @@ -45,7 +47,7 @@ public class MethodEntry { } @Override - public int hashCode() { + public int hashCode(){ return targetMethod.hashCode(); } } diff --git a/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java b/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java index 037ec8129a..b0402b2c55 100644 --- a/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java +++ b/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java @@ -18,25 +18,25 @@ import java.util.*; import java.util.stream.Collectors; -/**The annotation processor for generating remote method call code.*/ +/** The annotation processor for generating remote method call code. */ @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({ - "io.anuke.annotations.Annotations.Remote", - "io.anuke.annotations.Annotations.WriteClass", - "io.anuke.annotations.Annotations.ReadClass", + "io.anuke.annotations.Annotations.Remote", + "io.anuke.annotations.Annotations.WriteClass", + "io.anuke.annotations.Annotations.ReadClass", }) -public class RemoteMethodAnnotationProcessor extends AbstractProcessor { - /**Maximum size of each event packet.*/ +public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ + /** Maximum size of each event packet. */ public static final int maxPacketSize = 4096; - /**Name of the base package to put all the generated classes.*/ + /** Name of the base package to put all the generated classes. */ private static final String packageName = "io.anuke.mindustry.gen"; - /**Name of class that handles reading and invoking packets on the server.*/ + /** Name of class that handles reading and invoking packets on the server. */ private static final String readServerName = "RemoteReadServer"; - /**Name of class that handles reading and invoking packets on the client.*/ + /** Name of class that handles reading and invoking packets on the client. */ private static final String readClientName = "RemoteReadClient"; - /**Processing round number.*/ + /** Processing round number. */ private int round; //class serializers @@ -51,7 +51,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { private ArrayList classes; @Override - public synchronized void init(ProcessingEnvironment processingEnv) { + public synchronized void init(ProcessingEnvironment processingEnv){ super.init(processingEnv); //put all relevant utils into utils class Utils.typeUtils = processingEnv.getTypeUtils(); @@ -61,15 +61,15 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean process(Set annotations, RoundEnvironment roundEnv){ if(round > 1) return false; //only process 2 rounds - round ++; + round++; - try { + try{ //round 1: find all annotations, generate *writers* - if(round == 1) { + if(round == 1){ //get serializers serializers = new IOFinder().findSerializers(roundEnv); @@ -88,21 +88,21 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { orderedElements.sort(Comparator.comparing(Object::toString)); //create methods - for (Element element : orderedElements) { + for(Element element : orderedElements){ Remote annotation = element.getAnnotation(Remote.class); //check for static - if (!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)) { + if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){ Utils.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element); } //can't generate none methods - if (annotation.targets() == Loc.none) { + if(annotation.targets() == Loc.none){ Utils.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element); } //get and create class entry if needed - if (!classMap.containsKey(annotation.in())) { + if(!classMap.containsKey(annotation.in())){ ClassEntry clas = new ClassEntry(annotation.in()); classMap.put(annotation.in(), clas); classes.add(clas); @@ -127,7 +127,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { writegen.generateFor(classes, packageName); return true; - }else if(round == 2) { //round 2: generate all *readers* + }else if(round == 2){ //round 2: generate all *readers* RemoteReadGenerator readgen = new RemoteReadGenerator(serializers); //generate server readers @@ -147,7 +147,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { return true; } - }catch (Exception e){ + }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); } diff --git a/annotations/src/io/anuke/annotations/RemoteReadGenerator.java b/annotations/src/io/anuke/annotations/RemoteReadGenerator.java index ae2ab83de7..5898e369a1 100644 --- a/annotations/src/io/anuke/annotations/RemoteReadGenerator.java +++ b/annotations/src/io/anuke/annotations/RemoteReadGenerator.java @@ -14,22 +14,25 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; -/**Generates code for reading remote invoke packets on the client and server.*/ -public class RemoteReadGenerator { +/** Generates code for reading remote invoke packets on the client and server. */ +public class RemoteReadGenerator{ private final HashMap serializers; - /**Creates a read generator that uses the supplied serializer setup.*/ - public RemoteReadGenerator(HashMap serializers) { + /** Creates a read generator that uses the supplied serializer setup. */ + public RemoteReadGenerator(HashMap serializers){ this.serializers = serializers; } - /**Generates a class for reading remote invoke packets. + /** + * Generates a class for reading remote invoke packets. + * * @param entries List of methods to use/ * @param className Simple target class name. * @param packageName Full target package name. - * @param needsPlayer Whether this read method requires a reference to the player sender.*/ + * @param needsPlayer Whether this read method requires a reference to the player sender. + */ public void generateFor(List entries, String className, String packageName, boolean needsPlayer) - throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException { + throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{ TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); @@ -69,10 +72,10 @@ public class RemoteReadGenerator { StringBuilder varResult = new StringBuilder(); //go through each parameter - for(int i = 0; i < entry.element.getParameters().size(); i ++){ + for(int i = 0; i < entry.element.getParameters().size(); i++){ VariableElement var = entry.element.getParameters().get(i); - if(!needsPlayer || i != 0) { //if client, skip first parameter since it's always of type player and doesn't need to be read + if(!needsPlayer || i != 0){ //if client, skip first parameter since it's always of type player and doesn't need to be read //full type name of parameter String typeName = var.asType().toString(); //name of parameter @@ -81,17 +84,17 @@ public class RemoteReadGenerator { String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); //write primitives automatically - if (Utils.isPrimitive(typeName)) { - if (typeName.equals("boolean")) { + if(Utils.isPrimitive(typeName)){ + if(typeName.equals("boolean")){ readBlock.addStatement("boolean " + varName + " = buffer.get() == 1"); - } else { + }else{ readBlock.addStatement(typeName + " " + varName + " = buffer.get" + capName + "()"); } - } else { + }else{ //else, try and find a serializer ClassSerializer ser = serializers.get(typeName); - if (ser == null) { //make sure a serializer exists! + if(ser == null){ //make sure a serializer exists! Utils.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var); return; } @@ -121,7 +124,7 @@ public class RemoteReadGenerator { } readBlock.nextControlFlow("catch (java.lang.Exception e)"); - readBlock.addStatement("throw new java.lang.RuntimeException(\"Failed to to read remote method '"+entry.element.getSimpleName() +"'!\", e)"); + readBlock.addStatement("throw new java.lang.RuntimeException(\"Failed to to read remote method '" + entry.element.getSimpleName() + "'!\", e)"); readBlock.endControlFlow(); } diff --git a/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java b/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java index 1d80dcbc67..86502f96a3 100644 --- a/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java +++ b/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java @@ -14,17 +14,17 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; -/**Generates code for writing remote invoke packets on the client and server.*/ -public class RemoteWriteGenerator { +/** Generates code for writing remote invoke packets on the client and server. */ +public class RemoteWriteGenerator{ private final HashMap serializers; - /**Creates a write generator that uses the supplied serializer setup.*/ - public RemoteWriteGenerator(HashMap serializers) { + /** Creates a write generator that uses the supplied serializer setup. */ + public RemoteWriteGenerator(HashMap serializers){ this.serializers = serializers; } - /**Generates all classes in this list.*/ - public void generateFor(List entries, String packageName) throws IOException { + /** Generates all classes in this list. */ + public void generateFor(List entries, String packageName) throws IOException{ for(ClassEntry entry : entries){ //create builder @@ -58,7 +58,7 @@ public class RemoteWriteGenerator { } } - /**Creates a specific variant for a method entry.*/ + /** Creates a specific variant for a method entry. */ private void writeMethodVariant(TypeSpec.Builder classBuilder, MethodEntry methodEntry, boolean toAll, boolean forwarded){ ExecutableElement elem = methodEntry.element; @@ -99,7 +99,7 @@ public class RemoteWriteGenerator { if(!forwarded && methodEntry.local != Loc.none){ //add in local checks if(methodEntry.local != Loc.both){ - method.beginControlFlow("if("+getCheckString(methodEntry.local) + " || !io.anuke.mindustry.net.Net.active())"); + method.beginControlFlow("if(" + getCheckString(methodEntry.local) + " || !io.anuke.mindustry.net.Net.active())"); } //concatenate parameters @@ -109,16 +109,16 @@ public class RemoteWriteGenerator { //special case: calling local-only methods uses the local player if(index == 0 && methodEntry.where == Loc.client){ results.append("io.anuke.mindustry.Vars.players[0]"); - }else { + }else{ results.append(var.getSimpleName()); } if(index != elem.getParameters().size() - 1) results.append(", "); - index ++; + index++; } //add the statement to call it method.addStatement("$N." + elem.getSimpleName() + "(" + results.toString() + ")", - ((TypeElement)elem.getEnclosingElement()).getQualifiedName().toString()); + ((TypeElement) elem.getEnclosingElement()).getQualifiedName().toString()); if(methodEntry.local != Loc.both){ method.endControlFlow(); @@ -126,10 +126,10 @@ public class RemoteWriteGenerator { } //start control flow to check if it's actually client/server so no netcode is called - method.beginControlFlow("if("+getCheckString(methodEntry.where)+")"); + method.beginControlFlow("if(" + getCheckString(methodEntry.where) + ")"); //add statement to create packet from pool - method.addStatement("$1N packet = $2N.obtain($1N.class)", "io.anuke.mindustry.net.Packets.InvokePacket", "com.badlogic.gdx.utils.Pools"); + method.addStatement("$1N packet = $2N.obtain($1N.class)", "io.anuke.mindustry.net.Packets.InvokePacket", "io.anuke.ucore.util.Pooling"); //assign buffer method.addStatement("packet.writeBuffer = TEMP_BUFFER"); //assign priority @@ -139,7 +139,7 @@ public class RemoteWriteGenerator { //rewind buffer method.addStatement("TEMP_BUFFER.position(0)"); - for(int i = 0; i < elem.getParameters().size(); i ++){ + for(int i = 0; i < elem.getParameters().size(); i++){ //first argument is skipped as it is always the player caller if((!methodEntry.where.isServer/* || methodEntry.mode == Loc.both*/) && i == 0){ continue; @@ -164,7 +164,7 @@ public class RemoteWriteGenerator { method.beginControlFlow("if(io.anuke.mindustry.net.Net.server())"); } - if(Utils.isPrimitive(typeName)) { //check if it's a primitive, and if so write it + if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it if(typeName.equals("boolean")){ //booleans are special method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)"); }else{ @@ -181,7 +181,7 @@ public class RemoteWriteGenerator { } //add statement for writing it - method.addStatement(ser.writeMethod + "(TEMP_BUFFER, " + varName +")"); + method.addStatement(ser.writeMethod + "(TEMP_BUFFER, " + varName + ")"); } if(writePlayerSkipCheck){ //write end check @@ -197,7 +197,7 @@ public class RemoteWriteGenerator { if(forwarded){ //forward packet if(!methodEntry.local.isClient){ //if the client doesn't get it called locally, forward it back after validation sendString = "send("; - }else { + }else{ sendString = "sendExcept(exceptSenderID, "; } }else if(toAll){ //send to all players / to server @@ -207,8 +207,8 @@ public class RemoteWriteGenerator { } //send the actual packet - method.addStatement("io.anuke.mindustry.net.Net." + sendString + "packet, "+ - (methodEntry.unreliable ? "io.anuke.mindustry.net.Net.SendMode.udp" : "io.anuke.mindustry.net.Net.SendMode.tcp")+")"); + method.addStatement("io.anuke.mindustry.net.Net." + sendString + "packet, " + + (methodEntry.unreliable ? "io.anuke.mindustry.net.Net.SendMode.udp" : "io.anuke.mindustry.net.Net.SendMode.tcp") + ")"); //end check for server/client @@ -220,7 +220,7 @@ public class RemoteWriteGenerator { private String getCheckString(Loc loc){ return loc.isClient && loc.isServer ? "io.anuke.mindustry.net.Net.server() || io.anuke.mindustry.net.Net.client()" : - loc.isClient ? "io.anuke.mindustry.net.Net.client()" : - loc.isServer ? "io.anuke.mindustry.net.Net.server()" : "false"; + loc.isClient ? "io.anuke.mindustry.net.Net.client()" : + loc.isServer ? "io.anuke.mindustry.net.Net.server()" : "false"; } } diff --git a/annotations/src/io/anuke/annotations/Utils.java b/annotations/src/io/anuke/annotations/Utils.java index d379a2d257..551d953bc4 100644 --- a/annotations/src/io/anuke/annotations/Utils.java +++ b/annotations/src/io/anuke/annotations/Utils.java @@ -7,14 +7,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; -public class Utils { +public class Utils{ public static Types typeUtils; public static Elements elementUtils; public static Filer filer; public static Messager messager; public static String getMethodName(Element element){ - return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); + return ((TypeElement) element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); } public static boolean isPrimitive(String type){ diff --git a/build.gradle b/build.gradle index cd13ee0ad0..8939f41ed4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { dependencies { classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.0' classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6' - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.1.3' classpath "com.badlogicgames.gdx:gdx-tools:1.9.8" } } @@ -27,7 +27,7 @@ allprojects { gdxVersion = '1.9.8' roboVMVersion = '2.3.0' aiVersion = '1.8.1' - uCoreVersion = '2241e5402e' + uCoreVersion = 'c502931313' getVersionString = { String buildVersion = getBuildVersion() diff --git a/core/assets-raw/sprites/blocks/distribution/multiplexer.png b/core/assets-raw/sprites/blocks/distribution/distributor.png similarity index 100% rename from core/assets-raw/sprites/blocks/distribution/multiplexer.png rename to core/assets-raw/sprites/blocks/distribution/distributor.png diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-0.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-0.png new file mode 100644 index 0000000000..04eca38d45 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-0.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-1.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-1.png new file mode 100644 index 0000000000..dff4e78e7f Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-1.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-2.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-2.png new file mode 100644 index 0000000000..5fec0419e0 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-2.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-3.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-3.png new file mode 100644 index 0000000000..8983671a0d Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-3.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-4.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-4.png new file mode 100644 index 0000000000..3a8d3ac7a8 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-4.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png new file mode 100644 index 0000000000..5fa2763614 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-5.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png new file mode 100644 index 0000000000..931b4d5b87 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom-6.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-bottom.png b/core/assets-raw/sprites/blocks/liquid/conduit-bottom.png index a869a8cdae..7e3892102f 100644 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-bottom.png and b/core/assets-raw/sprites/blocks/liquid/conduit-bottom.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-0.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-0.png new file mode 100644 index 0000000000..c3809b0f60 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-0.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-1.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-1.png new file mode 100644 index 0000000000..37ee6de2a6 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-1.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-2.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-2.png new file mode 100644 index 0000000000..635972c5bc Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-2.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-3.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-3.png new file mode 100644 index 0000000000..e067a5bb7b Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-3.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-4.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-4.png new file mode 100644 index 0000000000..ad90c44566 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-4.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png new file mode 100644 index 0000000000..7941306123 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-5.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png b/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png new file mode 100644 index 0000000000..eb0cdfbb25 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/conduit-top-6.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/conduit-top.png b/core/assets-raw/sprites/blocks/liquid/conduit-top.png deleted file mode 100644 index 8a9894c8b5..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/conduit-top.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-bottom.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-bottom.png deleted file mode 100644 index 304dc71403..0000000000 Binary files a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-bottom.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/liquid/pulse-conduit-top.png rename to core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-0.png diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-1.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-1.png new file mode 100644 index 0000000000..43017050e7 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-1.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-2.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-2.png new file mode 100644 index 0000000000..7796332524 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-2.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-3.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-3.png new file mode 100644 index 0000000000..4ae0db8bf1 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-3.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-4.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-4.png new file mode 100644 index 0000000000..b90b2a51b2 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-4.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png new file mode 100644 index 0000000000..74aedc579e Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-5.png differ diff --git a/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png new file mode 100644 index 0000000000..30c4e4bcc2 Binary files /dev/null and b/core/assets-raw/sprites/blocks/liquid/pulse-conduit-top-6.png differ diff --git a/core/assets-raw/sprites/ui/icons/icon-item.png b/core/assets-raw/sprites/ui/icons/icon-item.png new file mode 100644 index 0000000000..0e99951b81 Binary files /dev/null and b/core/assets-raw/sprites/ui/icons/icon-item.png differ diff --git a/core/assets-raw/sprites/ui/icons/icon-missing.png b/core/assets-raw/sprites/ui/icons/icon-missing.png new file mode 100644 index 0000000000..fcae107678 Binary files /dev/null and b/core/assets-raw/sprites/ui/icons/icon-missing.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index a33590bc35..3e9976024d 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -55,13 +55,7 @@ text.about.button=About text.name=Name: text.unlocked=New Block Unlocked! text.unlocked.plural=New Blocks Unlocked! -text.server.rollback=Rollback -text.server.rollback.numberfield=Rollback Amount: -text.blocks.editlogs=Edit Logs -text.block.editlogsnotfound=[red]There are no edit logs for this location. -text.public=Public text.players={0} players online -text.server.player.host={0} (host) text.players.single={0} player online text.server.mismatch=Packet error: possible client/server version mismatch.\nMake sure you and the host have the\nlatest version of Mindustry! text.server.closing=[accent]Closing server... @@ -118,7 +112,6 @@ text.confirmban=Are you sure you want to ban this player? text.confirmunban=Are you sure you want to unban this player? text.confirmadmin=Are you sure you want to make this player an admin? text.confirmunadmin=Are you sure you want to remove admin status from this player? -text.joingame.byip=Join by IP... text.joingame.title=Join Game text.joingame.ip=IP: text.disconnect=Disconnected. @@ -130,8 +123,7 @@ text.server.port=Port: text.server.addressinuse=Address already in use! text.server.invalidport=Invalid port number! text.server.error=[crimson]Error hosting server: [orange]{0} -text.tutorial.back=< Prev -text.tutorial.next=Next > +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. text.save.new=New Save text.save.overwrite=Are you sure you want to overwrite\nthis save slot? text.overwrite=Overwrite @@ -141,7 +133,7 @@ text.savefail=Failed to save game! text.save.delete.confirm=Are you sure you want to delete this save? text.save.delete=Delete text.save.export=Export Save -text.save.import.invalid=[orange]This save is invalid!\n\nNote that[scarlet]importing saves with custom maps[orange]\nfrom other devices does not work! +text.save.import.invalid=[orange]This save is invalid! text.save.import.fail=[crimson]Failed to import save: [orange]{0} text.save.export.fail=[crimson]Failed to export save: [orange]{0} text.save.import=Import Save @@ -226,21 +218,13 @@ text.editor.exportimage.description=Export a map image file text.editor.loadimage=Import Terrain text.editor.saveimage=Export Terrain text.editor.unsaved=[scarlet]You have unsaved changes![]\nAre you sure you want to exit? -text.editor.brushsize=Brush size: {0} -text.editor.noplayerspawn=This map has no player spawnpoint! -text.editor.manyplayerspawns=Maps cannot have more than one\nplayer spawnpoint! -text.editor.manyenemyspawns=Cannot have more than\n{0} enemy spawnpoints! text.editor.resizemap=Resize Map -text.editor.resizebig=[scarlet]Warning!\n[]Maps larger than 256 units may be laggy and unstable. text.editor.mapname=Map Name: text.editor.overwrite=[accent]Warning!\nThis overwrites an existing map. text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? text.editor.selectmap=Select a map to load: text.width=Width: text.height=Height: -text.randomize=Randomize -text.apply=Apply -text.update=Update text.menu=Menu text.play=Play text.load=Load @@ -269,7 +253,6 @@ text.yes=Yes text.no=No text.info.title=[accent]Info text.error.title=[crimson]An error has occured -text.error.crashmessage=[SCARLET]An unexpected error has occured, which would have caused a crash.\n[]Please report the exact circumstances under which this error occured to the developer: \n[ORANGE]anukendev@gmail.com[] text.error.crashtitle=An error has occured text.blocks.blockinfo=Block Info text.blocks.powercapacity=Power Capacity @@ -297,6 +280,10 @@ text.blocks.drilltier=Drillables text.blocks.drillspeed=Base Drill Speed text.blocks.liquidoutput=Liquid Output text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use text.blocks.explosive=Highly explosive! text.blocks.health=Health text.blocks.inaccuracy=Inaccuracy @@ -332,7 +319,6 @@ setting.difficulty.insane=insane setting.difficulty.purge=purge setting.difficulty.name=Difficulty: setting.screenshake.name=Screen Shake -setting.smoothcam.name=Smooth Camera setting.indicators.name=Enemy Indicators setting.effects.name=Display Effects setting.sensitivity.name=Controller Sensitivity @@ -343,10 +329,8 @@ setting.multithread.name=Multithreading setting.fps.name=Show FPS setting.vsync.name=VSync setting.lasers.name=Show Power Lasers -setting.previewopacity.name=Placing Preview Opacity setting.healthbars.name=Show Entity Health bars setting.minimap.name=Show Minimap -setting.pixelate.name=Pixelate Screen setting.musicvol.name=Music Volume setting.mutemusic.name=Mute Music setting.sfxvol.name=SFX Volume @@ -454,15 +438,15 @@ block.conveyor.name=Conveyor block.titanium-conveyor.name=Titanium Conveyor block.junction.name=Junction block.splitter.name=Splitter -block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.splitter.description=Outputs items into three different directions once they are recieved. block.router.name=Router block.router.description=Splits items into all 4 directions. Can store items as a buffer. -block.multiplexer.name=Multiplexer -block.multiplexer.description=A router that can split items into 8 directions. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. block.sorter.name=Sorter block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. -block.overflowgate.name=Overflow Gate -block.overflowgate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. block.bridgeconveyor.name=Bridge Conveyor block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. block.smelter.name=Smelter @@ -512,7 +496,6 @@ block.swarmer.name=Swarmer block.salvo.name=Salvo block.ripple.name=Ripple block.phase-conveyor.name=Phase Conveyor -block.overflow-gate.name=Overflow Gate block.bridge-conveyor.name=Bridge Conveyor block.plastanium-compressor.name=Plastanium Compressor block.pyratite-mixer.name=Pyratite Mixer diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 2439a197cd..78b1bf4794 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -1,479 +1,495 @@ -text.about = Erstellt von [ROYAL] Anuken. [] \nUrsprünglich ein Eintrag im [orange] GDL [] MM Jam.\n\nCredits: \n- SFX gemacht mit [yellow] bfxr [] - Musik gemacht von [green] RoccoW [] / gefunden auf [lime] FreeMusicArchive.org [] \n\nBesonderer Dank geht an: \n- [coral] MitchellFJN []: Umfangreicher Spieletest und Feedback \n- [sky] Luxray5474 []: Wiki-Arbeit, Code-Beiträge \n- Alle Beta-Tester auf itch.io und Google Play\n -text.discord = Trete dem Mindustry Discord bei! -text.gameover = Der Kern wurde zerstört. -text.highscore = [YELLOW] Neuer Highscore! -text.lasted = Du hast bis zur folgenden Welle überlebt -text.level.highscore = High Score: [accent] {0} -text.level.delete.title = Löschen bestätigen -text.level.delete = Bist du sicher, dass du die Karte \"[orange] {0}\" löschen möchtest? -text.level.select = Level Auswahl -text.level.mode = Spielmodus: -text.savegame = Spiel speichern -text.loadgame = Spiel laden -text.joingame = Spiel beitreten -text.quit = Verlassen -text.about.button = Info -text.name = Name: -text.public = Öffentlich -text.players = {0} Spieler online -text.players.single = {0} Spieler online -text.server.mismatch = Paketfehler: Mögliche Client / Server-Version stimmt nicht überein. Stell sicher, dass du und der Host die neueste Version von Mindustry haben! -.server.closing = [accent] Server wird geschlossen... -text.server.kicked.kick = Du wurdest vom Server gekickt! -text.server.kicked.invalidPassword = Falsches Passwort. -text.server.connected = {0} ist beigetreten -text.server.disconnected = {0} hat die Verbindung getrennt. -text.nohost = Server kann nicht auf einer benutzerdefinierten Karte gehostet werden! -text.hostserver = Server hosten -text.host = Host -text.hosting = [accent] Server wird geöffnet... -text.hosts.refresh = Aktualisieren -text.hosts.discovering = Suche nach LAN-Spielen -text.server.refreshing = Server wird aktualisiert -text.hosts.none = [lightgray] Keine LAN Spiele gefunden! -text.host.invalid = [scarlet] Kann keine Verbindung zum Host herstellen. -text.server.add = Server hinzufügen -text.server.delete = Bist du dir sicher das du diesen Server löschen möchtest? -text.server.hostname = Host: {0} -text.server.edit = Server bearbeiten -text.joingame.byip = Über IP beitreten ... -text.joingame.title = Spiel beitreten -text.joingame.ip = IP: -text.disconnect = Verbindung unterbrochen. -text.connecting = [accent] Verbindet... -text.connecting.data = [accent] Weltdaten werden geladen... -text.connectfail = [crimson] Verbindung zum Server konnte nicht hergestellt werden: [orange]{0} -text.server.port = Port: -text.server.invalidport = Falscher Port! -text.server.error = [crimson] Fehler beim Hosten des Servers: [orange] {0} -text.tutorial.back = < Zurück -text.tutorial.next = Weiter > -text.save.new = Neuer Spielstand -text.save.overwrite = Möchten du diesen Spielstand wirklich überschreiben? -text.overwrite = Überschreiben -text.save.none = Keine Spielstände gefunden! -text.saveload = [accent] Speichern ... -text.savefail = Fehler beim Speichern des Spiels! -text.save.delete.confirm = Möchtest du diesen Spielstand wirklich löschen? -text.save.delete = Löschen -text.save.export = Spielstand exportieren -text.save.import.invalid = [orange] Dieser Spielstand ist ungültig! -text.save.import.fail = [crimson] Spielstand konnte nicht importiert werden: [orange] {0} -text.save.export.fail = [crimson] Spielstand konnte nicht exportiert werden: [orange] {0} -text.save.import = Spielstand importieren -text.save.newslot = Name speichern: -text.save.rename = Umbenennen -text.save.rename.text = Neuer Name -text.selectslot = Wähle einen Spielstand -text.slot = [accent] Platz {0} -text.save.corrupted = [orange] Datei beschädigt oder ungültig! -text.empty = -text.on = An -text.off = Aus -text.save.autosave = Automatisches Speichern: {0} -text.save.map = Karte: {0} -text.save.wave = Welle: {0} -text.save.date = Zuletzt gespeichert: {0} -text.confirm = Bestätigen -text.delete = Löschen -text.ok = OK -text.open = Öffnen -text.cancel = Abbruch -text.openlink = Link öffnen -text.back = Zurück -text.quit.confirm = Willst du wirklich aufhören? -text.loading = [accent] Wird geladen ... -text.wave = [orange] Welle {0} -text.wave.waiting = Welle in {0} -text.waiting = Warten... -text.enemies = {0} Feinde -text.enemies.single = {0} Feind -text.loadimage = Bild laden -text.saveimage = Bild speichern -text.editor.badsize = [orange]Ungültige Bildabmessungen! [] Gültige Kartenabmessungen: {0} -text.editor.errorimageload = Fehler beim Laden des Bildes: [orange] {0} -text.editor.errorimagesave = Fehler beim Speichern des Bildes: [orange] {0} -text.editor.generate = Generieren -text.editor.resize = Grösse\nanpassen -text.editor.loadmap = Karte\nladen -text.editor.savemap = Karte\nspeichern -text.editor.loadimage = Bild\nladen -text.editor.saveimage = Bild\nspeichern -text.editor.unsaved = [crimson] Du hast Änderungen nicht gespeichert [] Möchtest du wirklich aufhören? -text.editor.brushsize = Pinselgrösse: {0} -text.editor.noplayerspawn = Diese Karte hat keinen Spielerspawnpunkt! -text.editor.manyplayerspawns = Maps können nicht mehr als einen Spawnpunkt des Spielers haben! -text.editor.manyenemyspawns = Kann nicht mehr als {0} feindliche Spawnpunkte haben! -text.editor.resizemap = Grösse der Karte ändern -text.editor.resizebig = [crimson] Warnung! [] Karten, die grösser als 256 Einheiten sind, können ruckeln und instabil sein. -text.editor.mapname = Map Name -text.editor.overwrite = [accent] Warnung! Dies überschreibt eine vorhandene Map. -text.editor.failoverwrite = [crimson] Die Standardkarte kann nicht überschrieben werden! -text.editor.selectmap = Wähle eine Map zum Laden: -text.width = Breite: -text.height = Höhe: -text.randomize = Zufällig -text.apply = Anwenden -text.update = Aktualisieren -text.menu = Menü -text.play = Spielen -text.load = Laden -text.save = Speichern -text.settings = Einstellungen -text.tutorial = Tutorial -text.editor = Bearbeiter -text.mapeditor = Karten Bearbeiter -text.donate = Spenden -text.settings.reset = Auf Standard zurücksetzen -text.settings.controls = Steuerung -text.settings.game = Spiel -text.settings.sound = Audio -text.settings.graphics = Grafiken -text.upgrades = Verbesserungen -text.purchased = [LIME] Erstellt! -text.weapons = Waffen -text.paused = Pausiert -text.respawn = Respawn in -text.error.title = [crimson] Ein Fehler ist aufgetreten -text.error.crashmessage = [SCARLET] Es ist ein unerwarteter Fehler aufgetreten, der einen Absturz verursacht hätte. [] Bitte geben Sie die genauen Umstände an, unter denen dieser Fehler passiert ist, für den Entwickler: [ORANGE] anukendev@gmail.com [] -text.error.crashtitle = EIn Fehler ist aufgetreten! -text.mode.break = Zerstörungsmodus: {0} -text.mode.place = Platzierungsmodus: {0} -placemode.hold.name = Zeile -placemode.areadelete.name = Gebiet -placemode.touchdelete.name = berühren -placemode.holddelete.name = halten -placemode.none.name = keine -placemode.touch.name = berühren -placemode.cursor.name = Mauszeiger -text.blocks.extrainfo = [accent] Extra Blockinfo: -text.blocks.blockinfo = Blockinfo: -text.blocks.powercapacity = Energiekapazität -text.blocks.powershot = Energie / Schuss -text.blocks.powersecond = Energie / Sekunde -text.blocks.powerdraindamage = Energieabnahme / Schaden -text.blocks.shieldradius = Schildradius -text.blocks.itemspeedsecond = Gegenstands Geschwindigkeit / Sekunde -text.blocks.range = Reichweite -text.blocks.size = Grösse -text.blocks.powerliquid = Energie / Flüssigkeit -text.blocks.maxliquidsecond = Max Flüssigkeit / Sekunde -text.blocks.liquidcapacity = Flüssigkeitskapazität -text.blocks.liquidsecond = Flüssigkeit / Sekunde -text.blocks.damageshot = Schaden / Schuss -text.blocks.ammocapacity = Munitionskapazität -text.blocks.ammo = Munition -text.blocks.ammoitem = Munition / Gegenstand -text.blocks.maxitemssecond = Max Gegenstände / Sekunde -text.blocks.powerrange = Energiereichweite -text.blocks.lasertilerange = Laser Reichweite -text.blocks.capacity = Kapazität -text.blocks.itemcapacity = Gegenstand Kapazität -text.blocks.maxpowergenerationsecond = Max Energieerzeugung / Sekunde -text.blocks.powergenerationsecond = Energieerzeugung / Sekunde -text.blocks.generationsecondsitem = Generation Sekunden / Gegenstand -text.blocks.input = Eingabe -text.blocks.inputliquid = Flüssigkeiten Eingabe -text.blocks.inputitem = Eingabe Gegenstand -text.blocks.output = Ausgabe -text.blocks.secondsitem = Sekunden / Item -text.blocks.maxpowertransfersecond = Max Energieübertragung / Sekunde -text.blocks.explosive = Hochexplosiv! -text.blocks.repairssecond = Reparaturen / Sekunde -text.blocks.health = Lebenspunkte -text.blocks.inaccuracy = Ungenauigkeit -text.blocks.shots = Schüsse -text.blocks.shotssecond = Schüsse / Sekunde -text.blocks.fuel = Treibstoff -text.blocks.fuelduration = Treibstoffdauer -text.blocks.maxoutputsecond = Max Ausgabe / Sekunde -text.blocks.inputcapacity = Eingabekapazität -text.blocks.outputcapacity = Ausgabekapazität -text.blocks.poweritem = Energie / Gegenstand -text.placemode = Platzierungsmodus -text.breakmode = Zerstörungsmodus -text.health = Lebenspunkte -setting.difficulty.easy = Leicht -setting.difficulty.normal = Normal -setting.difficulty.hard = Schwer -setting.difficulty.insane = Unmöglich -setting.difficulty.purge = Auslöschung -setting.difficulty.name = Schwierigkeit -setting.screenshake.name = Bildschirm wackeln -setting.smoothcam.name = Glatte Kamera -setting.indicators.name = Feind Indikatoren -setting.effects.name = Effekte anzeigen -setting.sensitivity.name = Kontroller Empfindlichkeit -setting.saveinterval.name = Autosave Häufigkeit -setting.seconds = {0} Sekunden -setting.fps.name = Zeige FPS -setting.vsync.name = VSync -setting.lasers.name = Zeige Energielaser -setting.healthbars.name = Zeige Objekt Lebensbalken -setting.pixelate.name = Pixel Bildschirm -setting.musicvol.name = Musiklautstärke -setting.mutemusic.name = Musik stummschalten -setting.sfxvol.name = Audioeffekte Lautstärke -setting.mutesound.name = Audioeffekte stummschalten -map.maze.name = Labyrinth -map.fortress.name = Festung -map.sinkhole.name = Sinkloch -map.caves.name = Höhlen -map.volcano.name = Vulkan -map.caldera.name = Lavakessel -map.scorch.name = Flammen -map.desert.name = Wüste -map.island.name = Insel -map.grassland.name = Grasland -map.tundra.name = Kältesteppe -map.spiral.name = Spirale -map.tutorial.name = Tutorial -tutorial.intro.text = [gelb] Willkommen zum Tutorial [] Um zu beginnen, drücke 'weiter'. -tutorial.moveDesktop.text = Verwende zum Verschieben die Tasten [orange] [[WASD] []. Halte [orange] Shift [] gedrückt, um zu erhöhen. Halte [orange] CTRL/STRG [] gedrückt, während du das [orange] Scrollrad [] zum Vergrössern oder Verkleinern verwendest. -tutorial.shoot.text = Ziele mit der Maus, halte die [orange] linke Maustaste [] gedrückt, um zu schiessen. Versuche es mit dem [gelben] Ziel []. -tutorial.moveAndroid.text = Um die Ansicht zu verschieben, ziehe einen Finger über den Bildschirm. Drücke und ziehe, um zu vergrössern oder zu verkleinern. -tutorial.placeSelect.text = Versuche, ein [gelbes] Förderband [] aus dem Blockmenü unten rechts auszuwählen. -tutorial.placeConveyorDesktop.text = Verwende das [orange] [[scrollwheel] [], um das Förderband nach vorne zu bewegen [orange] vorwärts [], und platziere es dann an der [gelben] markierten Stelle [] mit [orange] [[linke Maustaste] []. -tutorial.placeConveyorAndroid.text = Verwende die [orange] [[rotieren-Taste] [], um das Förderband nach vorne [orange] zu drehen [], ziehe es mit einem Finger in Position und platziere es dann an der [gelben] markierten Stelle [] mit der [Orange] [[Häkchen][]. -tutorial.placeConveyorAndroidInfo.text = Alternativ kannst du das Fadenkreuzsymbol unten links drücken, um zum [orange] [[touch mode] [] zu wechseln, und Blöcke durch Tippen auf den Bildschirm platzieren. Im Touch-Modus können Blöcke mit dem Pfeil unten links gedreht werden. Drücke [gelb] neben [], um es auszuprobieren. -tutorial.placeDrill.text = Wähle nun einen [gelben] Steinbohrer [] an der markierten Stelle aus und platziere ihn. -tutorial.blockInfo.text = Wenn du mehr über einen Block erfahren möchtest, tippe oben rechts auf das [orange] Fragezeichen [], um dessen Beschreibung zu lesen. -tutorial.deselectDesktop.text = Du kannst einen Block mit [Orange] [[Rechte Maustaste] [] abwählen. -tutorial.deselectAndroid.text = Du kannst einen Block abwählen, indem du die [orange] X [] -Taste drücken. -tutorial.drillPlaced.text = Der Bohrer erzeugt nun [gelben] Stein, [] gib den Stein nun auf das Förderband aus und bewege ihn dann in den [gelben] Kern []. -tutorial.drillInfo.text = Verschiedene Erze benötigen unterschiedliche Bohrer. Stein erfordert Steinbohrer, Eisen erfordert Eisenbohrer usw. -tutorial.drillPlaced2.text = Wenn du Gegenstände in den Kern verschiebst, steckst du sie in dein [gelbes] Inventar [] oben links. Das Platzieren von Blöcken verwendet Gegenstände aus deinem Inventar. -tutorial.moreDrills.text = Du kannst so viele Bohrer und Förderer miteinander verbinden wie du lust hast. -tutorial.deleteBlock.text = Du kannst Blöcke löschen, indem du mit der [orange] rechte Maustaste [] auf dem Block klickst, den du löschen möchtest. Versuche, dieses Förderband zu löschen. -tutorial.deleteBlockAndroid.text = Du kannst Blöcke löschen, indem du [orange] das Fadenkreuz [] im [orange] Pausenmodusmenü [] links unten auswählst und auf einen Block tippst. Versuche, dieses Fliessband zu löschen. -tutorial.placeTurret.text = Wähle nun einen [gelben] Turm [] an der [gelben] markierten Stelle [] und platziere ihn. -tutorial.placedTurretAmmo.text = Dieser Turm nimmt nun [gelbe] Munition [] vom Förderband an. Du kannst sehen, wie viel Munition es hat, indem du darüber schweben und den [grünen] grünen Balken [] prüfen. -tutorial.turretExplanation.text = Geschütze schiessen automatisch auf den nächsten Feind in Reichweite, solange sie genug Munition haben. -tutorial.waves.text = Jede [yellow] 60 [] Sekunden wird eine Welle von [coral] Feinden [] an einem bestimmten Orten erscheinen und versuchen, den Kern zu zerstören. -tutorial.coreDestruction.text = Dein Ziel ist es, den Kern [yellow] zu verteidigen. Wenn der Kern zerstört wird, verlierst du [coral] das Spiel []. -tutorial.pausingDesktop.text = Wenn du jemals eine Pause machen möchtest, drücke die [orange] Pause-Taste [] oben links oder [orange]space[], um das Spiel anzuhalten. Du kannst auch Blöcke immer noch auswählen und platzieren, während du das Spiel pausiert ist, aber Sie können sich nicht bewegen oder schiessen. -tutorial.pausingAndroid.text = Wenn du jemals eine Pause machen willst, drück einfach die [orange] Pause-Taste [] oben links, um das Spiel anzuhalten. Sie können immer noch Sachen auswählen und Blöcke während der Pause platzieren. -tutorial.purchaseWeapons.text = Du kannst neue [yellow] Waffen [] für deinen Mech kaufen, indem du das Verbesserungs-Menü unten links öffnest. -tutorial.switchWeapons.text = Schalte Waffen, indem du entweder auf das Symbol unten links klickst oder Nummern verwendest [orange] [[1-9] []. -tutorial.spawnWave.text = Hier kommt die erste Welle. Zerstöre sie. -tutorial.pumpDesc.text = In späteren Wellen müsst du möglicherweise [yellow] Pumpen [] verwenden, um Flüssigkeiten für Generatoren oder Extraktoren zu verteilen. -tutorial.pumpPlace.text = Pumpen arbeiten ähnlich wie Bohrer, ausser dass sie anstelle von Gegenständen Flüssigkeiten produzieren. Versuch mal, eine Pumpe auf das [yellow] gekennzeichnete Öl [] zu setzen. -tutorial.conduitUse.text = Stellen Sie nun eine [orange] Leitungsrohr [] von der Pumpe weg. -tutorial.conduitUse2.text = Und noch ein paar mehr ... -tutorial.conduitUse3.text = Und noch ein paar mehr ... -tutorial.generator.text = Stellen Sie nun einen [orange] Verbrennungsgenerator [] Block am Ende des Leitungsrohres auf. -tutorial.generatorExplain.text = Dieser Generator erzeugt nun [yellow] Energie [] aus dem Öl. -tutorial.lasers.text = Die Energie wird mit [yellow] Energielasern [] verteilt. Drehe und platziere einen hier. -tutorial.laserExplain.text = Der Generator wird nun Energie in den Laserblock bewegen. Ein [yellow] undurchsichtiger [] Strahl bedeutet, dass er gerade Leistung überträgt, und ein [yellow] transparenter [] Strahl bedeutet, dass dies nicht der Fall ist. -tutorial.laserMore.text = Du kannst überprüfen, wie viel Energie ein Block hat, indem du darüber schweben und den [yellow] gelben Balken [] oben prüfen. -tutorial.healingTurret.text = Dieser Laser kann verwendet werden, um einen [lime] -Reparaturgeschütz [] anzutreiben. Platziere einen hier. -tutorial.healingTurretExplain.text = Solange er Kraft hat, repariert dieser Turm in der Nähe Blöcke. [] Wenn du spielst, stelle sicher, dass du so schnell wie möglich einen in deiner Basis bekommst! -tutorial.smeltery.text = Viele Blöcke benötigen [orange] Stahl [], um eine [orange] Schmelzer [] herzustellen. Platziere einen hier. -tutorial.smelterySetup.text = Diese Schmelzer wird nun [orange] Stahl [] aus dem Eingangs-Eisen produzieren, wobei Kohle als Brennstoff verwendet wird. -tutorial.end.text = Und damit ist das Tutorial abgeschlossen! Viel Glück! -keybind.move_x.name = bewege_x -keybind.move_y.name = bewege_y -keybind.select.name = wählen -keybind.break.name = Unterbrechung -keybind.shoot.name = Schiess -keybind.zoom_hold.name = zoomen_halten -keybind.zoom.name = zoomen -keybind.menu.name = Menü -keybind.pause.name = Pause -keybind.dash.name = Bindestrich -keybind.rotate_alt.name = drehen_alt -keybind.rotate.name = Drehen -keybind.weapon_1.name = Waffe_1 -keybind.weapon_2.name = Waffe_2 -keybind.weapon_3.name = Waffe_3 -keybind.weapon_4.name = Waffe_4 -keybind.weapon_5.name = Waffe_5 -keybind.weapon_6.name = Waffe_6 -mode.waves.name = Wellen -mode.sandbox.name = Sandkasten -mode.freebuild.name = Freier Bau -upgrade.standard.name = Standard -upgrade.standard.description = Der Standardmech. -upgrade.blaster.name = Blaster -upgrade.blaster.description = Schiesst eine langsame, schwache Kugel. -upgrade.triblaster.name = Dreifach-Blaster -upgrade.triblaster.description = Schiesst 3 Kugeln in einer Ausbreitung. -upgrade.clustergun.name = Klumpen-Waffe -upgrade.clustergun.description = Schiesst eine ungenaue Verbreitung von explosiven Granaten. -upgrade.beam.name = Strahlkanone -upgrade.beam.description = Schiesst einen weitreichenden durchdringenden Laserstrahl. -upgrade.vulcan.name = Vulkan -upgrade.vulcan.description = Schiesst eine Flut von schnellen Kugeln. -upgrade.shockgun.name = Schock-Waffe -upgrade.shockgun.description = Erschiesst eine verheerende Explosion von geladenen Granatsplittern. -item.stone.name = Stein -item.iron.name = Eisen -item.coal.name = Kohle -item.steel.name = Stahl -item.titanium.name = Titan -item.dirium.name = Dirium -item.thorium.name = Uran -item.sand.name = Sand -liquid.water.name = Wasser -liquid.plasma.name = Plasma -liquid.lava.name = Lava -liquid.oil.name = Öl -block.weaponfactory.name = Waffenfabrik -block.air.name = Luft -block.blockpart.name = Blockteil -block.deepwater.name = tiefes Wasser -block.water.name = Wasser -block.lava.name = Lava -block.oil.name = Öl -block.stone.name = Stein -block.blackstone.name = schwarzer Stein -block.iron.name = Eisen -block.coal.name = Kohle -block.titanium.name = Titan -block.thorium.name = Uran -block.dirt.name = Erde -block.sand.name = Sand -block.ice.name = Eis -block.snow.name = Schnee -block.grass.name = Gras -block.sandblock.name = Sandstein -block.snowblock.name = Schneeblock -block.stoneblock.name = Steinblock -block.blackstoneblock.name = Schwarzer Stein -block.grassblock.name = Grasblock -block.mossblock.name = Moosblock -block.shrub.name = Busch -block.rock.name = Felsen -block.icerock.name = Eisfelsen -block.blackrock.name = Schwarzer Felsen -block.dirtblock.name = Erdblock -block.stonewall.name = Steinwand -block.stonewall.fulldescription = Ein billiger Verteidigungsblock. Nützlich zum Schutz des Kerns und der Geschütztürme in den ersten Wellen. -block.ironwall.name = Eisenwand -block.ironwall.fulldescription = Ein grundlegender Verteidigungsblock. Bietet Schutz vor Feinden. -block.steelwall.name = Stahlwand -block.steelwall.fulldescription = Ein Standard-Verteidigungsblock. Bietet angemessen Schutz vor Feinden. -block.titaniumwall.name = Titanwand -block.titaniumwall.fulldescription = Eine starke Abwehrblockade. Bietet Schutz vor Feinden. -block.duriumwall.name = Diriumwand -block.duriumwall.fulldescription = Eine sehr starke Abwehrblockade. Bietet guten Schutz vor Feinden. -block.compositewall.name = Verbundende Wand -block.steelwall-large.name = grosse Stahlwand -block.steelwall-large.fulldescription = Ein Standard-Verteidigungsblock. Mehrere Blöcke gross. -block.titaniumwall-large.name = grosse Titanwand -block.titaniumwall-large.fulldescription = Eine starke Abwehrblockade. Mehrere Blöcke gross. -block.duriumwall-large.name = grosse Diriumwand -block.duriumwall-large.fulldescription = Eine sehr starke Abwehrblockade. Mehrere Blöcke gross. -block.titaniumshieldwall.name = geschützte Wand -block.titaniumshieldwall.fulldescription = Ein starker Abwehrblock mit einem extra eingebauten Schild. Benötigt Energie. Verwendet Energie, um feindliche Kugeln zu absorbieren. Es wird empfohlen, Verstärker zu verwenden, um diesem Block Energie zuzuführen. -block.repairturret.name = Reparaturgeschütz -block.repairturret.fulldescription = Repariert beschädigte Blöcke in der Nähe in einem langsamen Tempo. Nutzt geringe Mengen an Energie. -block.megarepairturret.name = Reparaturgeschütz II -block.megarepairturret.fulldescription = Repariert in der Nähe beschädigte Blöcke in Reichweite zu einem vernünftigen Preis. Verwendet Energie. -block.shieldgenerator.name = Schildgenerator -block.shieldgenerator.fulldescription = Ein fortgeschrittener Verteidigungsblock. Schützt alle Blöcke in einem Radius vor Angriffen. Bei keinem Betrieb langsamer Strom verbrauch, verliert bei Kugelkontakt jedoch schnell Energie. -block.door.name = Tür -block.door.fulldescription = Ein Block, der durch Antippen geöffnet und geschlossen werden kann. -block.door-large.name = grosse Tür -block.door-large.fulldescription = Ein Block der mehrere Felder gross ist und der durch Antippen geöffnet und geschlossen werden kann. -block.conduit.name = Leitungsrohr -block.conduit.fulldescription = Grundlegender Flüssigkeitstransportblock. Funktioniert wie ein Förderband, aber mit Flüssigkeiten. Am besten mit Pumpen oder anderen Leitungen verwenden. Kann als Brücke für Gegner und Spieler verwendet werden. -block.pulseconduit.name = Pulsleitungsrohr -block.pulseconduit.fulldescription = Fortschrittlicher Flüssigkeitstransportblock. Transportiert Flüssigkeiten schneller und speichert mehr als normale Leitungsrohre. -block.liquidrouter.name = flüssigkeiten verteiler -block.liquidrouter.fulldescription = Funktioniert ähnlich wie ein Router. Akzeptiert Flüssigkeit von einer Seite und gibt sie auf die anderen Seiten aus. Nützlich zum Aufspalten von Flüssigkeit aus eines einzelnen Leitungsrohres in mehrere andere Leitungensrohre. -block.conveyor.name = Förderband -block.conveyor.fulldescription = Grundelement Transport Block. Bewegt Gegenstände nach vorne und legt sie automatisch in Türmen oder ähnliches. Drehbar. Kann als Brücke für Gegner und Spieler verwendet werden. -block.steelconveyor.name = Stahlförderband -block.steelconveyor.fulldescription = Erweiterter Transportblock Bewegt Gegenstände schneller als Standardförderer. -block.poweredconveyor.name = Impulsförderband -block.poweredconveyor.fulldescription = Der ultimative Transportblock für Gegenstände. Bewegt Gegenstände noch schneller als Stahlförderer. -block.router.name = Verteiler -block.router.fulldescription = Akzeptiert Objekte aus einer Richtung und gibt sie in 3 andere Richtungen aus. Kann auch eine bestimmte Anzahl von Gegenständen speichern. Geeignet zum Aufteilen der Materialien von einem Bohrer in mehrere Geschütze. -block.junction.name = Kreuzung -block.junction.fulldescription = Fungiert als Brücke für zwei kreuzende Förderbänder. Nützlich in Situationen mit zwei verschiedenen Förderbänder, die unterschiedliche Materialien zu verschiedenen Orten transportieren. -block.conveyortunnel.name = Förderbandtunnel -block.conveyortunnel.fulldescription = Transportiert Artikel unter Blöcken. Verwendung für einen Tunnel, der in den zu untertunnelnden Block führt, und einen auf der anderen Seite. Stellen Sie sicher, dass beide Tunnel in entgegengesetzte Richtungen weisen, das heisst das die Tunnel voneinander weggucken. -block.liquidjunction.name = flüssigkeite Kreuzung -block.liquidjunction.fulldescription = Funktioniert als Brücke für zwei kreuzende Leitungsrohre. Nützlich in Situationen mit zwei verschiedenen Leitungen, die unterschiedliche Flüssigkeiten zu verschiedenen Orten transportieren. -block.liquiditemjunction.name = Flüssigkeit-Gegenstand-Kreuzung -block.liquiditemjunction.fulldescription = Fungiert als Brücke zum Überqueren von Leitungsrohre und Förderbändern. -block.powerbooster.name = Energieverstärker -block.powerbooster.fulldescription = Verteilt die Energie an alle Blöcke innerhalb seines Radius. -block.powerlaser.name = Energielaser -block.powerlaser.fulldescription = Erzeugt einen Laser, der die Kraft auf den Block davor überträgt. Erzeugt selbst keine Energie. Am besten mit Generatoren oder anderen Lasern verwendet. -block.powerlaserrouter.name = Laser Verteiler -block.powerlaserrouter.fulldescription = Laser, der die Kraft in drei Richtungen gleichzeitig verteilt. Nützlich in Situationen, in denen mehrere Blöcke von einem Generator mit Strom versorgt werden müssen. -block.powerlasercorner.name = Laser-Ecke -block.powerlasercorner.fulldescription = Laser, der die Kraft in zwei Richtungen gleichzeitig verteilt. Nützlich in Situationen, in denen mehrere Blöcke von einem Generator mit Strom versorgt werden müssen und ein Router ungenau ist. -block.teleporter.name = Teleporter -block.teleporter.fulldescription = Erweiterter Transportblock Teleporter geben Gegenstände in andere Teleporter derselben Farbe ein. Tut nichts, wenn keine Teleporter derselben Farbe existieren. Wenn mehrere Teleporter mit derselben Farbe existieren, wird eine zufällige ausgewählt. Verwendet Energie. Tippen, um die Farbe zu ändern. -block.sorter.name = Sortierer -block.sorter.fulldescription = Sortiert den Gegenstand nach Materialart. Das zu akzeptierende Material wird durch die Farbe im Block angezeigt. Alle Artikel, die dem Sortiermaterial entsprechen, werden vorwärts ausgegeben, alles andere wird nach links und rechts ausgegeben. -block.core.name = Kern -block.pump.name = Pumpe -block.pump.fulldescription = Pumpen Flüssigkeiten aus einem Quellblock - meist Wasser, Lava oder Öl. Gibt Flüssigkeit in benachbarte Leitungsrohre aus. -block.fluxpump.name = flux Pumpe -block.fluxpump.fulldescription = Eine erweiterte Version der Pumpe. Speichert mehr Flüssigkeit und pumpt Flüssigkeit schneller. -block.smelter.name = Schmelzer -block.smelter.fulldescription = Der essentielle Bastelblock. Wenn 1x Eisen und 1x Kohle eingegeben wird, wird 1x Stahl ausgegeben. -block.crucible.name = Tiegel -block.crucible.fulldescription = Ein fortgeschrittener Handwerksblock. Braucht Kohle um zu funktionieren. Wenn 1x Titan und 1x Stahl eingegeben wird, wird 1x Dirium ausgegeben. -block.coalpurifier.name = Kohle-Extraktor -block.coalpurifier.fulldescription = Ein einfacher Extraktorblock. Gibt Kohle aus, wenn der Block mit grossen Mengen Wasser und Stein gefüllt wird. -block.titaniumpurifier.name = Titan-Extraktor -block.titaniumpurifier.fulldescription = Ein Standard-Extraktorblock. Gibt Titan aus wenn er mit grossen Mengen Wasser und Eisen gefüllt wird. -block.oilrefinery.name = Ölraffinerie -block.oilrefinery.fulldescription = Veredelt grosse Mengen Öl zu Kohle. Nützlich für die Betankung von Blöcken die Kohle benutzen wie z.b. Waffentürme, wenn Kohleadern knapp sind. -block.stoneformer.name = Steinformer -block.stoneformer.fulldescription = Verfestigt flüssige Lava zu Stein. Nützlich für die Herstellung von grossen Mengen von Stein für Kohle-Extraktor. -block.lavasmelter.name = Lava-Schmelzer -block.lavasmelter.fulldescription = Verwendet Lava, um Eisen zu Stahl schmelzen. Eine Alternative zum Schmelzer. Nützlich in Situationen, in denen Kohle knapp ist. -block.stonedrill.name = Steinbohrer -block.stonedrill.fulldescription = Der wesentliche Bohrer. Wenn er auf Steinplatten gelegt wird, gibt er Steine ​​mit einer langsamen Geschwindigkeit auf endlosen Zeit aus. -block.irondrill.name = Eisenbohrer -block.irondrill.fulldescription = Eine grundlegender Bohrer. Wenn es auf Eisenerz gelegt wird, gibt er Eisen auf endloser Zeit langsam aus. -block.coaldrill.name = Kohlenbohrer -block.coaldrill.fulldescription = Eine grundlegender Bohrer. Wenn es auf Kohleerz platziert wird, gibt er für endloser Zeit langsam Kohle aus. -block.thoriumdrill.name = Uran-Bohrer -block.thoriumdrill.fulldescription = Ein fortgeschrittener Bohrer. Wenn es auf Uranerz platziert wird, gibt er Uran mit einer langsamen Geschwindigkeit auf endloser Zeit ab. -block.titaniumdrill.name = Titan-Bohrer -block.titaniumdrill.fulldescription = Ein fortgeschrittener Bohrer. Wenn es auf Titanerz platziert wird, gibt er Titan langsam aus für undendlich langer Zeit -block.omnidrill.name = Omni-Bohrer -block.omnidrill.fulldescription = Der ultimative Bohrer. Baut in schnellem Tempo jegliches Erz ab. -block.coalgenerator.name = Kohle-Generator -block.coalgenerator.fulldescription = Der wesentliche Generator. Erzeugt Energie aus Kohle. Gibt Energie als Laser an seine 4 Seiten aus. -block.thermalgenerator.name = thermischer Generator -block.thermalgenerator.fulldescription = Erzeugt Energie aus Lava. Gibt Energie als Laser an seine 4 Seiten aus. -block.combustiongenerator.name = Verbrennungsgenerator -block.combustiongenerator.fulldescription = Erzeugt Energie aus Öl. Gibt Energie als Laser an seine 4 Seiten aus. -block.rtgenerator.name = RTG-Generator -block.rtgenerator.fulldescription = Erzeugt geringe Mengen an Energie aus dem radioaktiven Zerfall von Uran. Gibt Energie als Laser an seine 4 Seiten aus. -block.nuclearreactor.name = Kernreaktor -block.nuclearreactor.fulldescription = Eine erweiterte Version des RTG-Generators und der ultimative Energie Generator. Erzeugt Strom aus Uran. Erfordert konstante Wasserkühlung. Sehr heiss; explodiert heftig, wenn zu wenig Kühlmittel zugeführt wird. -block.turret.name = Geschütz -block.turret.fulldescription = Ein einfacher, billiger Turm. Verwendet Stein für Munition. Hat etwas mehr Reichweite als das Doppelgeschütz. -block.doubleturret.name = Doppelgeschütz -block.doubleturret.fulldescription = Eine etwas stärkere Version des Geschützes. Verwendet Stein für Munition. Hat deutlich mehr Schaden, hat aber eine geringere Reichweite. Schiesst zwei Kugeln. -block.machineturret.name = Gatling Geschütz -block.machineturret.fulldescription = Ein Standard-Allround-Turm. Verwendet Eisen für Munition. Hat eine schnelle Feuerrate mit gutem Schaden. -block.shotgunturret.name = Splittergeschütz -block.shotgunturret.fulldescription = Ein Standard-Turm. Verwendet Eisen für Munition. Schiesst 7 Kugeln auf einmal. Geringere Reichweite, aber höhere Schadensleistung als das Gatling Geschütz -block.flameturret.name = Flammenwerfer -block.flameturret.fulldescription = Fortschrittlicher Nahbereichswaffe. Verwendet Kohle für Munition. Hat eine sehr geringe Reichweite, aber sehr hohen Schaden. Gut für Nahkampf. Empfohlen für den Einsatz hinter Mauern. -block.sniperturret.name = Schienenkanone -block.sniperturret.fulldescription = Fortschrittliches Reichweitengeschütz. Verwendet Stahl für Munition. Sehr hoher Schaden, aber niedrige Feuerrate. Teuer zu verwenden, kann aber aufgrund seiner Reichweite weit entfernt von den feindlichen Linien platziert werden. -block.mortarturret.name = Flakgeschütz -block.mortarturret.fulldescription = Fortschrittlicher Flächen-Schaden Turm. Verwendet Kohle für Munition. Sehr langsame Feuerrate und Geschosse, aber sehr hoher Einzelziel- und Flächenschaden. Nützlich gegen grosse Mengen von Feinden. -block.laserturret.name = Laserturm -block.laserturret.fulldescription = Fortschrittlicher Einzelziel-Turm. Verwendet Strom. Guter Allround-Revolver für mittlere Reichweiten. Nur Einzelziel. Verfehlt nie. -block.waveturret.name = Teslakanone -block.waveturret.fulldescription = Erweiterter Mehrfach-Ziele-Turm. Verwendet Strom. Mittlere Reichweite. Verfehlt nie. Im Durchschnitt zu wenig Schaden, aber kann mehrere Feinde gleichzeitig mit Kettenblitz treffen. -block.plasmaturret.name = Plasmageschütz -block.plasmaturret.fulldescription = Hochentwickelte Version des Flammenwerfers. Verwendet Kohle als Munition. Sehr hoher Schaden, niedriger bis mittlerer Reichweite. -block.chainturret.name = Kettengeschütz -block.chainturret.fulldescription = Die ultimative Schnellfeuer Waffe. Verwendet Uran als Munition. Schiesst grosse Kugeln mit hoher Feuerrate. Mittlere Reichweite. Mehrere Felder gross. Hält extrem viel aus. -block.titancannon.name = Titan Kanone -block.titancannon.fulldescription = Die ultimative Langstrecken Kanone. Verwendet Uran als Munition. Schiesst grosse Flächen-Schadenden-Granaten mit einer mittleren Feuerrate ab. Lange Reichweite. Ist mehrere Felder gross. Hält extrem viel aus. -block.playerspawn.name = Spielerspawn -block.enemyspawn.name = Gegnerspawn +text.about=Erstellt von [ROYAL] Anuken. [] \nUrsprünglich ein Eintrag im [orange] GDL [] MM Jam.\n\nCredits: \n- SFX gemacht mit [yellow] bfxr [] - Musik gemacht von [green] RoccoW [] / gefunden auf [lime] FreeMusicArchive.org [] \n\nBesonderer Dank geht an: \n- [coral] MitchellFJN []: Umfangreicher Spieletest und Feedback \n- [sky] Luxray5474 []: Wiki-Arbeit, Code-Beiträge \n- Alle Beta-Tester auf itch.io und Google Play\n +text.discord=Trete dem Mindustry Discord bei! +text.gameover=Der Kern wurde zerstört. +text.highscore=[YELLOW] Neuer Highscore! +text.lasted=Du hast bis zur folgenden Welle überlebt +text.level.highscore=High Score: [accent] {0} +text.level.delete.title=Löschen bestätigen +text.level.select=Level Auswahl +text.level.mode=Spielmodus: +text.savegame=Spiel speichern +text.loadgame=Spiel laden +text.joingame=Spiel beitreten +text.quit=Verlassen +text.about.button=Info +text.name=Name: +text.players={0} Spieler online +text.players.single={0} Spieler online +text.server.mismatch=Paketfehler: Mögliche Client / Server-Version stimmt nicht überein. Stell sicher, dass du und der Host die neueste Version von Mindustry haben! +text.server.kicked.kick=Du wurdest vom Server gekickt! +text.server.kicked.invalidPassword=Falsches Passwort. +text.server.connected={0} ist beigetreten +text.server.disconnected={0} hat die Verbindung getrennt. +text.nohost=Server kann nicht auf einer benutzerdefinierten Karte gehostet werden! +text.hostserver=Server hosten +text.host=Host +text.hosting=[accent] Server wird geöffnet... +text.hosts.refresh=Aktualisieren +text.hosts.discovering=Suche nach LAN-Spielen +text.server.refreshing=Server wird aktualisiert +text.hosts.none=[lightgray] Keine LAN Spiele gefunden! +text.host.invalid=[scarlet] Kann keine Verbindung zum Host herstellen. +text.server.add=Server hinzufügen +text.server.delete=Bist du dir sicher das du diesen Server löschen möchtest? +text.server.hostname=Host: {0} +text.server.edit=Server bearbeiten +text.joingame.title=Spiel beitreten +text.joingame.ip=IP: +text.disconnect=Verbindung unterbrochen. +text.connecting=[accent] Verbindet... +text.connecting.data=[accent] Weltdaten werden geladen... +text.connectfail=[crimson] Verbindung zum Server konnte nicht hergestellt werden: [orange]{0} +text.server.port=Port: +text.server.invalidport=Falscher Port! +text.server.error=[crimson] Fehler beim Hosten des Servers: [orange] {0} +text.save.new=Neuer Spielstand +text.save.overwrite=Möchten du diesen Spielstand wirklich überschreiben? +text.overwrite=Überschreiben +text.save.none=Keine Spielstände gefunden! +text.saveload=[accent] Speichern ... +text.savefail=Fehler beim Speichern des Spiels! +text.save.delete.confirm=Möchtest du diesen Spielstand wirklich löschen? +text.save.delete=Löschen +text.save.export=Spielstand exportieren +text.save.import.invalid=[orange] Dieser Spielstand ist ungültig! +text.save.import.fail=[crimson] Spielstand konnte nicht importiert werden: [orange] {0} +text.save.export.fail=[crimson] Spielstand konnte nicht exportiert werden: [orange] {0} +text.save.import=Spielstand importieren +text.save.newslot=Name speichern: +text.save.rename=Umbenennen +text.save.rename.text=Neuer Name +text.selectslot=Wähle einen Spielstand +text.slot=[accent] Platz {0} +text.save.corrupted=[orange] Datei beschädigt oder ungültig! +text.empty= +text.on=An +text.off=Aus +text.save.autosave=Automatisches Speichern: {0} +text.save.map=Karte: {0} +text.save.wave=Welle: {0} +text.save.date=Zuletzt gespeichert: {0} +text.confirm=Bestätigen +text.delete=Löschen +text.ok=OK +text.open=Öffnen +text.cancel=Abbruch +text.openlink=Link öffnen +text.back=Zurück +text.quit.confirm=Willst du wirklich aufhören? +text.loading=[accent] Wird geladen ... +text.wave=[orange] Welle {0} +text.wave.waiting=Welle in {0} +text.waiting=Warten... +text.enemies={0} Feinde +text.enemies.single={0} Feind +text.loadimage=Bild laden +text.saveimage=Bild speichern +text.editor.badsize=[orange]Ungültige Bildabmessungen! [] Gültige Kartenabmessungen: {0} +text.editor.errorimageload=Fehler beim Laden des Bildes: [orange] {0} +text.editor.errorimagesave=Fehler beim Speichern des Bildes: [orange] {0} +text.editor.generate=Generieren +text.editor.resize=Grösse\nanpassen +text.editor.loadmap=Karte\nladen +text.editor.savemap=Karte\nspeichern +text.editor.loadimage=Bild\nladen +text.editor.saveimage=Bild\nspeichern +text.editor.unsaved=[crimson] Du hast Änderungen nicht gespeichert [] Möchtest du wirklich aufhören? +text.editor.resizemap=Grösse der Karte ändern +text.editor.mapname=Map Name +text.editor.overwrite=[accent] Warnung! Dies überschreibt eine vorhandene Map. +text.editor.selectmap=Wähle eine Map zum Laden: +text.width=Breite: +text.height=Höhe: +text.menu=Menü +text.play=Spielen +text.load=Laden +text.save=Speichern +text.settings=Einstellungen +text.tutorial=Tutorial +text.editor=Bearbeiter +text.mapeditor=Karten Bearbeiter +text.donate=Spenden +text.settings.reset=Auf Standard zurücksetzen +text.settings.controls=Steuerung +text.settings.game=Spiel +text.settings.sound=Audio +text.settings.graphics=Grafiken +text.upgrades=Verbesserungen +text.purchased=[LIME] Erstellt! +text.weapons=Waffen +text.paused=Pausiert +text.error.title=[crimson] Ein Fehler ist aufgetreten +text.error.crashtitle=EIn Fehler ist aufgetreten! +text.blocks.blockinfo=Blockinfo: +text.blocks.powercapacity=Energiekapazität +text.blocks.powershot=Energie / Schuss +text.blocks.size=Grösse +text.blocks.liquidcapacity=Flüssigkeitskapazität +text.blocks.maxitemssecond=Max Gegenstände / Sekunde +text.blocks.powerrange=Energiereichweite +text.blocks.itemcapacity=Gegenstand Kapazität +text.blocks.inputliquid=Flüssigkeiten Eingabe +text.blocks.inputitem=Eingabe Gegenstand +text.blocks.explosive=Hochexplosiv! +text.blocks.health=Lebenspunkte +text.blocks.inaccuracy=Ungenauigkeit +text.blocks.shots=Schüsse +text.blocks.inputcapacity=Eingabekapazität +text.blocks.outputcapacity=Ausgabekapazität +setting.difficulty.easy=Leicht +setting.difficulty.normal=Normal +setting.difficulty.hard=Schwer +setting.difficulty.insane=Unmöglich +setting.difficulty.purge=Auslöschung +setting.difficulty.name=Schwierigkeit +setting.screenshake.name=Bildschirm wackeln +setting.indicators.name=Feind Indikatoren +setting.effects.name=Effekte anzeigen +setting.sensitivity.name=Kontroller Empfindlichkeit +setting.saveinterval.name=Autosave Häufigkeit +setting.seconds={0} Sekunden +setting.fps.name=Zeige FPS +setting.vsync.name=VSync +setting.lasers.name=Zeige Energielaser +setting.healthbars.name=Zeige Objekt Lebensbalken +setting.musicvol.name=Musiklautstärke +setting.mutemusic.name=Musik stummschalten +setting.sfxvol.name=Audioeffekte Lautstärke +setting.mutesound.name=Audioeffekte stummschalten +map.maze.name=Labyrinth +map.fortress.name=Festung +map.sinkhole.name=Sinkloch +map.caves.name=Höhlen +map.volcano.name=Vulkan +map.caldera.name=Lavakessel +map.scorch.name=Flammen +map.desert.name=Wüste +map.island.name=Insel +map.grassland.name=Grasland +map.tundra.name=Kältesteppe +map.spiral.name=Spirale +map.tutorial.name=Tutorial +keybind.move_x.name=bewege_x +keybind.move_y.name=bewege_y +keybind.select.name=wählen +keybind.break.name=Unterbrechung +keybind.shoot.name=Schiess +keybind.zoom_hold.name=zoomen_halten +keybind.zoom.name=zoomen +keybind.menu.name=Menü +keybind.pause.name=Pause +keybind.dash.name=Bindestrich +keybind.rotate_alt.name=drehen_alt +keybind.rotate.name=Drehen +mode.waves.name=Wellen +mode.sandbox.name=Sandkasten +mode.freebuild.name=Freier Bau +item.stone.name=Stein +item.coal.name=Kohle +item.titanium.name=Titan +item.thorium.name=Uran +item.sand.name=Sand +liquid.water.name=Wasser +liquid.lava.name=Lava +liquid.oil.name=Öl +block.door.name=Tür +block.door-large.name=grosse Tür +block.conduit.name=Leitungsrohr +block.pulseconduit.name=Pulsleitungsrohr +block.liquidrouter.name=flüssigkeiten verteiler +block.conveyor.name=Förderband +block.router.name=Verteiler +block.junction.name=Kreuzung +block.liquidjunction.name=flüssigkeite Kreuzung +block.sorter.name=Sortierer +block.smelter.name=Schmelzer +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.newgame=New Game +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.closing=[accent]Closing server... +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.clientOutdated=Outdated client! Update your game! +text.server.kicked.serverOutdated=Outdated server! Ask the host to update! +text.server.kicked.banned=You are banned on this server. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.server.friendlyfire=Friendly Fire +text.trace=Trace Player +text.trace.playername=Player name: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Unique ID: [accent]{0} +text.trace.android=Android Client: [accent]{0} +text.trace.modclient=Custom Client: [accent]{0} +text.trace.totalblocksbroken=Total blocks broken: [accent]{0} +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.trace.lastblockbroken=Last block broken: [accent]{0} +text.trace.totalblocksplaced=Total blocks placed: [accent]{0} +text.trace.lastblockplaced=Last block placed: [accent]{0} +text.invalidid=Invalid client ID! Submit a bug report. +text.server.bans=Bans +text.server.bans.none=No banned players found! +text.server.admins=Admins +text.server.admins.none=No admins found! +text.server.outdated=[crimson]Outdated Server![] +text.server.outdated.client=[crimson]Outdated Client![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[yellow]Custom Build +text.confirmban=Are you sure you want to ban this player? +text.confirmunban=Are you sure you want to unban this player? +text.confirmadmin=Are you sure you want to make this player an admin? +text.confirmunadmin=Are you sure you want to remove admin status from this player? +text.disconnect.data=Failed to load world data! +text.server.addressinuse=Address already in use! +text.save.difficulty=Difficulty: {0} +text.copylink=Copy Link +text.changelog.title=Changelog +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.language.restart=Please restart your game for the language settings to take effect. +text.settings.language=Language +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.info.title=[accent]Info +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.fullscreen.name=Fullscreen +setting.multithread.name=Multithreading +setting.minimap.name=Show Minimap +text.keybind.title=Rebind Keys +keybind.block_info.name=block_info +keybind.chat.name=chat +keybind.player_list.name=player_list +keybind.console.name=console +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index af95e6b530..a8136b7ead 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -1,552 +1,495 @@ -text.about = Creado por [ROYAL]Anuken [] - [SKY] anukendev@gmail.com [] Originalmente una entrada en el [naranja] GDL [] Metal Monstrosity Jam. Créditos: - SFX hecho con [AMARILLO] bfxr [] - Música hecha por [VERDE] RoccoW [] / encontrado en [lime] FreeMusicArchive.org [] Agradecimientos especiales a: - [coral] MitchellFJN []: extensa prueba de juego y comentarios - [cielo] Luxray5474 []: trabajo wiki, contribuciones de código - [lime] Epowerj []: sistema de compilación de código, icono - Todos los probadores beta en itch.io y Google Play\n -text.credits = Créditos -text.discord = ¡Únete al Discord de Mindustry! -text.changes = [SCARLET] ¡Atención! [] Algunas mecánicas importantes del juego han sido cambiadas. - [acento] Los teletransportadores [] ahora usan energía. - [acento]Los talleres de fundición[] y [acento]los crisoles [] ahora tienen una capacidad máxima de artículos. - [acento] Los crisoles[] ahora requieren carbón como combustible. -text.link.discord.description = La sala oficial del discord de Mindustry -text.link.github.description = Código fuente del juego -text.link.dev-builds.description = Estados en desarrollo inestables -text.link.trello.description = Tablero trello oficial para las características planificadas -text.link.itch.io.description = itch.io és la página con descargas para PC y la versión web -text.link.google-play.description = Listado en la tienda de Google Play -text.link.wiki.description = Wiki oficial de Mindustry -text.linkfail = ¡Error al abrir el enlace!\nLa URL ha sido copiada a su portapapeles -text.editor.web = ¡La versión web no es compatible con el editor!\nDescargue el juego para usarlo. -text.multiplayer.web = ¡Esta versión del juego no admite multijugador!\nPara jugar al modo multijugador desde su navegador, use el enlace \"versión de varios jugadores\" en la página itch.io. -text.gameover = El núcleo fue destruido. -text.highscore = [YELLOW]¡Nueva mejor puntuación! -text.lasted = Duró hasta la ronda -text.level.highscore = Puntuación màs alta: [accent] -text.level.delete.title = Confirmar Eliminación -text.level.delete = ¿Seguro que quieres eliminar el mapa \"[ORANGE] \" {0}? -text.level.select = Selección de nivel -text.level.mode = Modo de juego: -text.savegame = Guardar Partida -text.loadgame = Cargar Partida -text.joingame = Unirse a una Partida -text.newgame = Nueva Partida -text.quit = Salir -text.about.button = Acerca de -text.name = Nombre -text.public = Público -text.players = {0} Jugadores en línea -text.server.player.host = {0} ANFITRIÓN -text.players.single = {0} jugador en línea -text.server.mismatch = Error de paquete: posible desajuste de la versión cliente / servidor.\n¡Asegúrate de que tú y el anfitrión tengáis la última versión de Mindustry! -text.server.closing = [accent] Cerrando servidor ... -text.server.kicked.kick = ¡Has sido expulsado del servidor! -text.server.kicked.invalidPassword = ¡Contraseña inválida! -text.server.kicked.clientOutdated = Cliente desactualizado ¡Actualiza tu juego! -text.server.kicked.serverOutdated = Servidor desactualizado ¡Pidele actualizar al anfitrión! -text.server.kicked.banned = Tu entrada está prohibida en este servidor. -text.server.kicked.recentKick = Has sido echado recientemente.\nEspera antes de conectarte de nuevo. -text.server.connected = se ha unido. -text.server.disconnected = se ha desconectado -text.nohost = ¡No se puede alojar el servidor en un mapa personalizado! -text.host.info = El botón [acento] host [] aloja un servidor en los puertos [escarlata] 6567 [] y [escarlata] 6568. [] Cualquiera en el mismo [LIGHT_GRAY] wifi o red local [] debería poder ver su servidor en su servidor lista. Si desea que las personas puedan conectarse desde cualquier lugar mediante IP, se requiere [acento] reenvío de puerto []. [LIGHT_GRAY] Nota: Si alguien tiene problemas para conectarse a su juego LAN, asegúrese de haber permitido a Mindustry el acceso a su red local en la configuración de su firewall. -text.join.info = Aquí puede ingresar un servidor [acento] IP [] para conectarse, o descubrir servidores de [acento] red local [] para conectarse. Tanto el modo multijugador LAN como WAN son compatibles. [LIGHT_GRAY] Nota: no hay una lista de servidores global automática; si desea conectarse con alguien por IP, deberá solicitar al host su IP. -text.hostserver = Hostear servidor -text.host = Hostear -text.hosting = [acento] Abriendo servidor ... -text.hosts.refresh = Refrescar -text.hosts.discovering = Descubriendo juegos en LAN -text.server.refreshing = Servidor refrescante -text.hosts.none = [lightgray] ¡No se encontraron juegos LAN! -text.host.invalid = [escarlata] No se puede conectar al host. -text.server.friendlyfire = Fuego amigo -text.trace = Rastro del jugador -text.trace.playername = Nombre del jugador: [acento] {0} -text.trace.ip = IP: [acento] {0} -text.trace.id = ID único: [acento] {0} -text.trace.android = Cliente de Android: [acento] {0} -text.trace.modclient = Cliente personalizado: [acento] {0} -text.trace.totalblocksbroken = Total de bloques rotos: [acento] {0} -text.trace.structureblocksbroken = Bloques de estructura rotos: [acento] {0} -text.trace.lastblockbroken = Último bloque roto: [acento] {0} -text.trace.totalblocksplaced = Total de bloques colocados: [acento] {0} -text.trace.lastblockplaced = Último bloque colocado: [acento] {0} -text.invalidid = ID de cliente no válido Presente un informe del error. -text.server.bans = Baneos -text.server.bans.none = ¡No se encontraron jugadores baneados! -text.server.admins = Admins -text.server.admins.none = ¡No se encontraron administradores! -text.server.add = Agregar servidor -text.server.delete = ¿Seguro que quieres eliminar este servidor? -text.server.hostname = Anfitrión: {0} -text.server.edit = Editar servidor -text.server.outdated = [crimson] ¡Servidor obsoleto! [] -text.server.outdated.client = [carmesí] Cliente desactualizado! [] -text.server.version = [lightgray] Versión: {0} -text.server.custombuild = [amarillo] Creación personalizada -text.confirmban = ¿Estás seguro de que quieres prohibir este jugador? -text.confirmunban = ¿Estás seguro de que quieres desbloquear a este jugador? -text.confirmadmin = ¿Seguro que quieres que este jugador sea un administrador? -text.confirmunadmin = ¿Seguro que quieres eliminar el estado de administrador de este reproductor? -text.joingame.byip = Unirse por IP ... -text.joingame.title = Unirse a una partida -text.joingame.ip = IP: -text.disconnect = Desconectado. -text.disconnect.data = ¡Fallo al cargar datos mundiales! -text.connecting = [accent] Conectando ... -text.connecting.data = [accent] Cargando información del mapa... -text.connectfail = [crimson] Fallo al conectar al servidor: [orange] -text.server.port = Puerto: -text.server.addressinuse = ¡Dirección ya en uso! -text.server.invalidport = ¡Número de puerto inválido! -text.server.error = [crimson] Error en la creación del servidor: [orange] -text.tutorial.back = < Anterior -text.tutorial.next = Siguiente > -text.save.new = Nuevo Guardado -text.save.overwrite = ¿Seguro que quieres sobrescribir este juego guardado? -text.overwrite = Sobreescribir -text.save.none = ¡No hay juegos guardados! -text.saveload = [accent] Guardando... -text.savefail = ¡Error al guardar el juego! -text.save.delete.confirm = ¿Estás seguro de que deseas eliminar este guardado? -text.save.delete = Borrar -text.save.export = Exportar guardado -text.save.import.invalid = [orange] ¡Este guardado es inválido! -text.save.import.fail = [crimson] Fallo al importar guardado: [orange] {0} -text.save.export.fail = [crimson] Fallo al exportar guardado: [orange] {0} -text.save.import = Importar Guardado -text.save.newslot = Nombre del guardado: -text.save.rename = Renombrar -text.save.rename.text = Nuevo nombre -text.selectslot = Seleccionar una guardado -text.slot = [accent] Casilla {0} -text.save.corrupted = [orange] ¡Arhivo de guardado corrupto o inválido! -text.empty = -text.on = Encendido -text.off = Apagado -text.save.autosave = Guardado automático: {0} -text.save.map = Mapa: {0} -text.save.wave = Horda: {0} -text.save.difficulty = Dificultad: {0} -text.save.date = Guardado por última vez: {0} -text.confirm = Confirmar -text.delete = Eliiminar -text.ok = OK -text.open = Abrir -text.cancel = Cancelar -text.openlink = Abrir enlace -text.copylink = Copiar link -text.back = Atrás -text.quit.confirm = ¿Seguro que quieres salir? -text.changelog.title = Changelog -text.changelog.loading = Obteniendo changelog ... -text.changelog.error.android = [naranja] Tenga en cuenta que el registro de cambios no funciona en Android 4.4 y versiones posteriores. Esto se debe a un error interno de Android. -text.changelog.error = [escarlata] ¡Error al obtener el registro de cambios! Comprueba tu conexión a Internet. -text.changelog.current = [amarillo] [[Versión actual] -text.changelog.latest = [naranja] [[Última versión] -text.loading = [accent] Cargando... -text.wave = [orange] Horda {0} -text.wave.waiting = Horda en {0} -text.waiting = Esperando... -text.enemies = {0} Enemigos -text.enemies.single = {0} Enemigo -text.loadimage = Cargar imagen -text.saveimage = Guardar imagen -text.oregen = Generación de mineral {0} -text.editor.badsize = [orange]¡Dimensiones de imagen inválidas![]\nDimensiones de mapa válidas: {0} -text.editor.errorimageload = Error al cargar el archivo de imagen: [orange] {0} -text.editor.errorimagesave = Error al guardar el archivo de imagen: [orange] {0} -text.editor.generate = Generar -text.editor.resize = Cambiar tamaño -text.editor.loadmap = Cargar mapa -text.editor.savemap = Guardar mapa -text.editor.loadimage = Cargar imagen -text.editor.saveimage = Guardar imagen -text.editor.unsaved = [scarlet] ¡Tienes cambios sin guardar! [] ¿Estás seguro de que quieres salir? -text.editor.brushsize = Tamaño del pincel: {0} -text.editor.noplayerspawn = ¡Este mapa no tiene punto de aparición del jugador! -text.editor.manyplayerspawns = ¡Los mapas no pueden tener más de un punto de spawn de jugador! -text.editor.manyenemyspawns = {0 }¡No puede tener más de puntos de aparición enemiga! -text.editor.resizemap = Cambiar el tamaño del mapa -text.editor.resizebig = [escarlata] ¡Advertencia! [] Los mapas de más de 256 unidades pueden ser inestables. -text.editor.mapname = Nombre del mapa -text.editor.overwrite = [acento] ¡Advertencia!\nEsto sobrescribe un mapa existente. -text.editor.failoverwrite = [carmesí] ¡No se puede sobrescribir el mapa por defecto! -text.editor.selectmap = Seleccione un mapa para cargar: -text.width = Ancho: -text.height = Altura: -text.randomize = Aleatorizar -text.apply = Aplicar -text.update = Refrescar -text.menu = Menú -text.play = Jugar -text.load = Cargar -text.save = Salvar -text.language.restart = Por favor, reinicie su juego para que la configuración de idioma surta efecto. -text.settings.language = Idioma -text.settings = Ajustes -text.tutorial = Tutorial -text.editor = Editor -text.mapeditor = Editor de Mapas -text.donate = Donar -text.settings.reset = Restablecer los valores predeterminados -text.settings.controls = Controles -text.settings.game = Juego -text.settings.sound = Sonido -text.settings.graphics = Gráficos -text.upgrades = Mejoras -text.purchased = [LIME] Creado! -text.weapons = Armas -text.paused = Pausado -text.respawn = Reapareciendo en -text.info.title = [acento] Información -text.error.title = [carmesí] Se ha producido un error -text.error.crashmessage = [SCARLET] Se ha producido un error inesperado, que habría causado un bloqueo. [] Informe las circunstancias exactas bajo las cuales se produjo este error al desarrollador: [ORANGE] anukendev@gmail.com [] -text.error.crashtitle = Ha ocurrido un error -text.mode.break = Modo de eliminación: -text.mode.place = Modo de colocación: -placemode.hold.name = Línea -placemode.areadelete.name = Àrea -placemode.touchdelete.name = Toque -placemode.holddelete.name = Mantener -placemode.none.name = Ninguno -placemode.touch.name = Toque -placemode.cursor.name = Cursor -text.blocks.extrainfo = [acento] información adicional del bloque: -text.blocks.blockinfo = Información de bloque -text.blocks.powercapacity = Capacidad de energía -text.blocks.powershot = Energía/disparo -text.blocks.powersecond = energía drenada/segundo -text.blocks.powerdraindamage = Energía drenada/daño -text.blocks.shieldradius = Radio del escudo -text.blocks.itemspeedsecond = Velocidad del objeto/segundo -text.blocks.range = Rango -text.blocks.size = Tamaño -text.blocks.powerliquid = Poder/Líquido -text.blocks.maxliquidsecond = máximo líquido/segundo -text.blocks.liquidcapacity = Capacidad de liquido -text.blocks.liquidsecond = Líquido/segundo -text.blocks.damageshot = Daño/ disparo -text.blocks.ammocapacity = Capacidad de munición -text.blocks.ammo = Munición: -text.blocks.ammoitem = Munición/objeto -text.blocks.maxitemssecond = Objetos máximos/segundo -text.blocks.powerrange = Rango de energía -text.blocks.lasertilerange = Rango de poder en casilllas -text.blocks.capacity = Capacidad -text.blocks.itemcapacity = Capacidad de items -text.blocks.maxpowergenerationsecond = Máxima generación de energía/segundo -text.blocks.powergenerationsecond = Generación de energía/segundo -text.blocks.generationsecondsitem = Segundos de generación/Item -text.blocks.input = Ingreso -text.blocks.inputliquid = Entrada de líquidos -text.blocks.inputitem = Entrada de ítems -text.blocks.output = Salida -text.blocks.secondsitem = Segundos/Ítem -text.blocks.maxpowertransfersecond = Máxima transferencia de poder/segundo -text.blocks.explosive = ¡Altamente explosivo! -text.blocks.repairssecond = Reparado / segundo -text.blocks.health = Vida -text.blocks.inaccuracy = Inexactitud -text.blocks.shots = Disparos -text.blocks.shotssecond = Disparos / segundo -text.blocks.fuel = Combustible -text.blocks.fuelduration = Duración del combustible -text.blocks.maxoutputsecond = Máxima salida/segundo -text.blocks.inputcapacity = Capacidad de entrada -text.blocks.outputcapacity = Capacidad de salida -text.blocks.poweritem = Poder/Ítem -text.placemode = Modo colocar -text.breakmode = Modo romper -text.health = Salud -setting.difficulty.easy = Fácil -setting.difficulty.normal = Mormal -setting.difficulty.hard = Difícil -setting.difficulty.insane = Insano -setting.difficulty.purge = Purga -setting.difficulty.name = Dificultad: -setting.screenshake.name = Shake de pantalla -setting.smoothcam.name = Cámara lisa -setting.indicators.name = Indicador del enemigo -setting.effects.name = Mostrar efectos -setting.sensitivity.name = Sensibilidad del controlador -setting.saveinterval.name = Intervalo de autoguardado -setting.seconds = Segundos -setting.fullscreen.name = Pantalla completa -setting.multithread.name = Multithreading -setting.fps.name = Mostrar fps -setting.vsync.name = VSync -setting.lasers.name = Mostrar láseres de poder -setting.previewopacity.name = Colocando Vista Previa Opacidad -setting.healthbars.name = Mostrar barras de vida de enemigos y jugadores -setting.pixelate.name = Pixelear pantalla -setting.musicvol.name = Volumen de la música -setting.mutemusic.name = Apagar música -setting.sfxvol.name = Volumen de los efectos de sonido -setting.mutesound.name = Apagar sonidos -map.maze.name = Laberinto -map.fortress.name = Fortaleza -map.sinkhole.name = Sumidero -map.caves.name = Cuevas -map.volcano.name = Volcán -map.caldera.name = Caldera -map.scorch.name = Desierto volcánico -map.desert.name = Desierto -map.island.name = Isla -map.grassland.name = Pastizal -map.tundra.name = Tundra -map.spiral.name = Espiral -map.tutorial.name = Tutorial -tutorial.intro.text = [amarillo] Bienvenido al tutorial. [] Para comenzar, presione 'siguiente'. -tutorial.moveDesktop.text = Para moverse, use las teclas [naranja] [[WASD] []. Mantenga [naranja] shift [] para impulsar. Mantenga presionada la tecla [naranja] CTRL [] mientras usa la rueda de desplazamiento [naranja] [] para acercar o alejar la imagen. -tutorial.shoot.text = Usa el mouse para apuntar, mantén presionado [naranja] el botón izquierdo del mouse [] para disparar. Intenta practicar en el objetivo [amarillo] []. -tutorial.moveAndroid.text = Para recorrer la vista, arrastre un dedo por la pantalla. Pellizque y arrastre para acercar o alejar. -tutorial.placeSelect.text = Intente seleccionar un transportador [amarillo] [] desde el menú del bloque en la parte inferior derecha. -tutorial.placeConveyorDesktop.text = Utilice [naranja] [[rueda de desplazamiento] [] para girar la cinta transportadora hacia [naranja] hacia adelante [], luego colóquela en la ubicación [amarilla] marcada [] usando [naranja] [[botón izquierdo del mouse] []. -tutorial.placeConveyorAndroid.text = Utilice [naranja] [[girar el botón] [] para girar el transportador hacia [naranja] hacia delante [], arrástrelo con un dedo, luego colóquelo en la ubicación [amarilla] marcada [] usando [naranja] [[marca de verificación][]. -tutorial.placeConveyorAndroidInfo.text = Alternativamente, puede presionar el icono de la cruz en la parte inferior izquierda para cambiar a [naranja] [[modo táctil] [] y colocar bloques tocando en la pantalla. En modo táctil, los bloques se pueden girar con la flecha en la parte inferior izquierda. Presione [amarillo] al lado [] para probarlo. -tutorial.placeDrill.text = Ahora, seleccione y coloque un taladro de piedra [amarillo] [] en la ubicación marcada. -tutorial.blockInfo.text = Si desea obtener más información sobre un bloque, puede tocar el signo de interrogación [naranja] [] en la parte superior derecha para leer su descripción. -tutorial.deselectDesktop.text = Puede deseleccionar un bloque usando el [naranja] [[botón derecho del mouse] []. -tutorial.deselectAndroid.text = Puede deseleccionar un bloque presionando el botón [naranja] X []. -tutorial.drillPlaced.text = El taladro ahora producirá piedra [amarilla], [] la enviará al transportador y luego la moverá al núcleo [amarillo] []. -tutorial.drillInfo.text = Diferentes minerales necesitan diferentes ejercicios. La piedra requiere taladros de piedra, el hierro requiere taladros de hierro, etc. -tutorial.drillPlaced2.text = Mover elementos al núcleo los coloca en su inventario de elementos [amarillo] [], en la esquina superior izquierda. Colocar bloques utiliza elementos de tu inventario. -tutorial.moreDrills.text = Puede vincular muchos taladros y cintas transportadoras juntas, de esa manera. -tutorial.deleteBlock.text = Puede eliminar bloques haciendo clic en el botón [naranja] del botón derecho del mouse [] en el bloque que desea eliminar. Intente eliminar este transportador. -tutorial.deleteBlockAndroid.text = Puede eliminar bloques mediante [naranja] seleccionando la cruz [] en el menú [naranja] del modo de interrupción [] en la parte inferior izquierda y tocando un bloque. Intente eliminar este transportador. -tutorial.placeTurret.text = Ahora, seleccione y coloque una torreta [amarilla] [] en la ubicación marcada [amarilla] []. -tutorial.placedTurretAmmo.text = Esta torre ahora aceptará [amarillo] munición [] del transportador. Puedes ver la cantidad de munición que tiene al pasar el mouse sobre ella y verificar la barra verde [verde] []. -tutorial.turretExplanation.text = Las torretas dispararán automáticamente al enemigo más cercano al alcance, siempre que tengan suficiente munición. -tutorial.waves.text = Cada [amarillo] 60 [] segundos, una ola de [coral] enemigos [] aparecerán en lugares específicos e intentarán destruir el núcleo. -tutorial.coreDestruction.text = Tu objetivo es [amarillo] defender el núcleo []. Si se destruye el núcleo, tú [coral] pierdes el juego []. -tutorial.pausingDesktop.text = Si alguna vez necesita tomar un descanso, presione el botón de pausa [naranja] [] en el espacio superior izquierdo o [naranja] [] para detener el juego. Aún puede seleccionar y colocar bloques mientras está en pausa, pero no puede mover o disparar. -tutorial.pausingAndroid.text = Si alguna vez necesita tomarse un descanso, presione el botón de pausa [naranja] [] en la parte superior izquierda para pausar el juego. Todavía puede romper y colocar bloques mientras está en pausa. -tutorial.purchaseWeapons.text = Puedes comprar nuevas armas [amarillas] [] para tu mech abriendo el menú de actualización en la esquina inferior izquierda. -tutorial.switchWeapons.text = Cambie las armas haciendo clic en su icono en la esquina inferior izquierda o usando números [naranja] [[1-9] []. -tutorial.spawnWave.text = Aquí viene una ola ahora. Destruyelos. -tutorial.pumpDesc.text = En olas posteriores, es posible que deba usar bombas [amarillas] [] para distribuir líquidos para generadores o extractores. -tutorial.pumpPlace.text = Las bombas funcionan de manera similar a los taladros, excepto que producen líquidos en lugar de artículos. Intente colocar una bomba en el aceite designado [amarillo] []. -tutorial.conduitUse.text = Ahora coloque un conducto [naranja] [] que se aleje de la bomba. -tutorial.conduitUse2.text = Y algunos más ... -tutorial.conduitUse3.text = Y algunos más ... -tutorial.generator.text = Ahora, coloque un bloque [naranja] de generador de combustión [] al final del conducto. -tutorial.generatorExplain.text = Este generador ahora creará energía [amarilla] [] del aceite. -tutorial.lasers.text = La potencia se distribuye usando láseres de potencia [amarillos] []. Gira y coloca uno aquí. -tutorial.laserExplain.text = El generador ahora moverá energía al bloque láser. Un haz [amarillo] opaco [] significa que está transmitiendo corriente, y un haz [amarillo] transparente [] significa que no lo está. -tutorial.laserMore.text = Puedes verificar cuánta potencia tiene un bloque al pasar el mouse sobre él y verificar la barra amarilla [amarilla] [] en la parte superior. -tutorial.healingTurret.text = Este láser se puede usar para alimentar una torreta de reparación de [cal] []. Coloca uno aquí. -tutorial.healingTurretExplain.text = Mientras tenga energía, esta torreta [cal] reparará los bloques cercanos. [] ¡Al jugar, asegúrate de obtener uno en tu base lo más rápido posible! -tutorial.smeltery.text = Muchos bloques requieren [naranja] acero [] para fabricar, lo que requiere una fundición [naranja] [] para fabricar. Coloca uno aquí. -tutorial.smelterySetup.text = Esta fundición producirá acero [naranja] [] a partir de la plancha de entrada, utilizando carbón como combustible. -tutorial.tunnelExplain.text = También tenga en cuenta que los artículos pasan por un bloque de túnel [naranja] [] y salen del otro lado, pasando por el bloque de piedra. Tenga en cuenta que los túneles solo pueden atravesar hasta 2 bloques. -tutorial.end.text = ¡Y eso concluye el tutorial! ¡Buena suerte! -text.keybind.title = Vuelva a conectar las llaves -keybind.move_x.name = mover_x -keybind.move_y.name = mover_y -keybind.select.name = Elija -keybind.break.name = Romper -keybind.shoot.name = ¡Dispara! -keybind.zoom_hold.name = Enfoque_Mantener -keybind.zoom.name = Enfoquè -keybind.block_info.name = Bloque_informacion -keybind.menu.name = Menú -keybind.pause.name = Pausa -keybind.dash.name = Deslizar -keybind.chat.name = Chat -keybind.player_list.name = Jugadores_lista -keybind.console.name = Console -keybind.rotate_alt.name = Rotacion_alt -keybind.rotate.name = Girar -keybind.weapon_1.name = Arma_1 -keybind.weapon_2.name = Arma_2 -keybind.weapon_3.name = Arma_3\n -keybind.weapon_4.name = Arma_4 -keybind.weapon_5.name = Arma_5 -keybind.weapon_6.name = Arma6 -mode.text.help.title = Descripción de modos -mode.waves.name = Hordas -mode.waves.description = El modo normal. Recursos limitados y las hordas vendrán automáticamente -mode.sandbox.name = Sandbox -mode.sandbox.description = Recursos infinitos y sin temporizador para las olas. -mode.freebuild.name = Construcción libre -mode.freebuild.description = Recursos limitados y sin tiempo definido para las hordas -upgrade.standard.name = Estandar -upgrade.standard.description = El mech estándar. -upgrade.blaster.name = Blaster -upgrade.blaster.description = Dispara una bala lenta y débil. -upgrade.triblaster.name = Triblaster -upgrade.triblaster.description = Dispara 3 balas en una extensión. -upgrade.clustergun.name = Cleaster Gun -upgrade.clustergun.description = Dispara una propagación inexacta de granadas explosivas. -upgrade.beam.name = Cañòn Beam -upgrade.beam.description = Dispara un rayo láser perforante de largo alcance. -upgrade.vulcan.name = Volcán -upgrade.vulcan.description = Dispara una ráfaga de balas rapidas -upgrade.shockgun.name = Pistola Shock\n -upgrade.shockgun.description = Dispara una ráfaga devastadora de metralla cargada. -item.stone.name = Piedra -item.iron.name = Hierro -item.coal.name = Carbón -item.steel.name = Acero -item.titanium.name = Titanio -item.dirium.name = Dirio -item.uranium.name = Uranio -item.sand.name = Arena -liquid.water.name = Agua -liquid.plasma.name = Plasma -liquid.lava.name = Lava -liquid.oil.name = Aceite -block.weaponfactory.name = Fábrica de armas -block.weaponfactory.fulldescription = Se usa para crear armas para el jugador mech. Haga clic para usar. Automáticamente toma recursos del núcleo. -block.air.name = Aire -block.blockpart.name = Bloque -block.deepwater.name = Aguas profundas -block.water.name = Agua -block.lava.name = Lava -block.oil.name = Aceite -block.stone.name = Piedra -block.blackstone.name = Piedra Negra -block.iron.name = Hierro -block.coal.name = Carbón -block.titanium.name = Titanio -block.uranium.name = Uranio -block.dirt.name = Sucio -block.sand.name = Arena -block.ice.name = Hielo -block.snow.name = Nieve -block.grass.name = Césped -block.sandblock.name = Bloque de arena -block.snowblock.name = Bloque de nieve -block.stoneblock.name = Bloque de piedra -block.blackstoneblock.name = Bloque de piedra negra -block.grassblock.name = Bloque de césped -block.mossblock.name = Bloque de musgo -block.shrub.name = Arbusto -block.rock.name = Piedra -block.icerock.name = Piedra congelada -block.blackrock.name = Roca Negra -block.dirtblock.name = Bloque de suciedad -block.stonewall.name = Pared de piedra -block.stonewall.fulldescription = Un bloque defensivo barato. Útil para proteger el núcleo y las torrecillas en las primeras olas. -block.ironwall.name = Muro de hierro -block.ironwall.fulldescription = Un bloque defensivo básico. Proporciona protección de los enemigos. -block.steelwall.name = Muro de acero -block.steelwall.fulldescription = Un bloque defensivo estándar. protección adecuada de los enemigos. -block.titaniumwall.name = Muro de titanio -block.titaniumwall.fulldescription = Un fuerte bloqueo defensivo. Proporciona protección de los enemigos. -block.duriumwall.name = Muro de Dirio -block.duriumwall.fulldescription = Un bloque defensivo muy fuerte. Proporciona protección de los enemigos. -block.compositewall.name = Muro compuesto -block.steelwall-large.name = Pared de acero grande -block.steelwall-large.fulldescription = Un bloque defensivo estándar. Se extiende por múltiples mosaicos. -block.titaniumwall-large.name = Gran pared de titanio -block.titaniumwall-large.fulldescription = Un fuerte bloqueo defensivo. Se extiende por múltiples mosaicos. -block.duriumwall-large.name = Gran pared de dirio -block.duriumwall-large.fulldescription = Un bloque defensivo muy fuerte. Se extiende por múltiples mosaicos. -block.titaniumshieldwall.name = Muro blindado -block.titaniumshieldwall.fulldescription = Un fuerte bloque defensivo, con un escudo extra incorporado. Requiere poder Usa energía para absorber las balas enemigas. Se recomienda utilizar potenciadores de potencia para proporcionar energía a este bloque. -block.repairturret.name = Torreta de reparación -block.repairturret.fulldescription = Repara los bloques dañados cercanos en el rango a una velocidad lenta. Utiliza pequeñas cantidades de energía. -block.megarepairturret.name = Torreta de reparación II -block.megarepairturret.fulldescription = Repara los bloques dañados cercanos en el rango a una tasa decente. Utiliza el poder -block.shieldgenerator.name = Generador de escudo -block.shieldgenerator.fulldescription = Un bloque defensivo avanzado. Protege todos los bloques en un radio del ataque. Utiliza potencia a un ritmo lento cuando está inactivo, pero consume energía rápidamente al contacto con balas. -block.door.name = Puerta -block.door.fulldescription = Un bloque que se puede abrir y cerrar tocando. -block.door-large.name = Puerta grande -block.door-large.fulldescription = Un bloque que se puede abrir y cerrar tocando. -block.conduit.name = Conducto -block.conduit.fulldescription = Bloque de transporte de líquido básico. Funciona como un transportador, pero con líquidos. Se usa mejor con bombas u otros conductos. Se puede usar como puente sobre líquidos para enemigos y jugadores. -block.pulseconduit.name = Conducto de pulso -block.pulseconduit.fulldescription = Bloque de transporte de líquidos avanzado. Transporta líquidos más rápido y almacena más que los conductos estándar. -block.liquidrouter.name = Enrutador líquido -block.liquidrouter.fulldescription = Funciona de manera similar a un enrutador. Acepta entrada de líquido desde un lado y lo envía a los otros lados. Útil para dividir el líquido de un solo conducto en otros múltiples conductos. -block.conveyor.name = Transportador -block.conveyor.fulldescription = Bloque de transporte de elementos básicos. Mueve los artículos hacia adelante y los deposita automáticamente en torretas o crafters. Giratorio. Se puede usar como puente sobre líquidos para enemigos y jugadores. -block.steelconveyor.name = Transportador de acero -block.steelconveyor.fulldescription = Bloque de transporte de elementos avanzados. Mueve los artículos más rápido que los transportadores estándar. -block.poweredconveyor.name = Transportador de pulso -block.poweredconveyor.fulldescription = El último bloque de transporte de elementos. Mueve los artículos más rápido que los transportadores de acero. -block.router.name = Enrutador -block.router.fulldescription = Acepta elementos de una dirección y los envía a otras 3 direcciones. También puede almacenar una cierta cantidad de artículos. Útil para dividir los materiales de un taladro en múltiples torretas. -block.junction.name = Union -block.junction.fulldescription = Actúa como un puente para cruzar dos cintas transportadoras. Útil en situaciones con dos transportadores diferentes que llevan diferentes materiales a diferentes ubicaciones. -block.conveyortunnel.name = Túnel transportador -block.conveyortunnel.fulldescription = Transporta el artículo debajo de bloques. Para usarlo, coloque un túnel que conduce al bloque por el que se colocará el túnel, y otro del otro lado. Asegúrate de que ambos túneles estén orientados en direcciones opuestas, que se dirigen hacia los bloques a los que están ingresando o enviando. -block.liquidjunction.name = Unión líquida -block.liquidjunction.fulldescription = Actúa como un puente para dos conductos que cruzan. Útil en situaciones con dos conductos diferentes que llevan diferentes líquidos a diferentes lugares. -block.liquiditemjunction.name = Unión líquidos-elementos -block.liquiditemjunction.fulldescription = Actúa como un puente para cruzar conductos y transportadores. -block.powerbooster.name = Ampliación de potencia -block.powerbooster.fulldescription = Distribuye energía a todos los bloques dentro de su radio. -block.powerlaser.name = Láser de potencia -block.powerlaser.fulldescription = Crea un láser que transmite potencia al bloque que está delante de él. No genera ningún poder en sí mismo. Se usa mejor con generadores u otros láseres. -block.powerlaserrouter.name = Enrutador láser -block.powerlaserrouter.fulldescription = Láser que distribuye la potencia en tres direcciones a la vez. Útil en situaciones donde se requiere para alimentar múltiples bloques de un generador. -block.powerlasercorner.name = Laser esquinero -block.powerlasercorner.fulldescription = Láser que distribuye la potencia en dos direcciones a la vez. Útil en situaciones donde se requiere alimentar múltiples bloques desde un generador, y un enrutador es impreciso. -block.teleporter.name = Teletransportador -block.teleporter.fulldescription = Bloque de transporte de elementos avanzados. Los teleportadores ingresan elementos a otros teletransportadores del mismo color. No hace nada si no existen teletransportadores del mismo color. Si existen múltiples teleportadores del mismo color, se selecciona uno aleatorio. Utiliza el poder Toca para cambiar el color. -block.sorter.name = Clasificador -block.sorter.fulldescription = Ordena el artículo por tipo de material. El material a aceptar se indica por el color en el bloque. Todos los elementos que coinciden con el material de clasificación se envían hacia adelante, todo lo demás se envía a la izquierda y a la derecha. -block.core.name = Nùcleo -block.pump.name = Bomba -block.pump.fulldescription = Bombea líquidos de un bloque fuente, generalmente agua, lava o aceite. Emite líquido en los conductos cercanos. -block.fluxpump.name = Bomba de flujo -block.fluxpump.fulldescription = Una versión avanzada de la bomba. Almacena más líquido y bombea líquido más rápido. -block.smelter.name = horno de fundición -block.smelter.fulldescription = El bloque de elaboración esencial. Cuando se ingresa 1 hierro y 1 carbón como combustible, se emite un acero. Se aconseja ingresar hierro y carbón en diferentes bandas para evitar obstrucciones. -block.crucible.name = Crisol -block.crucible.fulldescription = Un bloque de elaboración avanzada. Cuando se ingresa 1 titanio, 1 acero y 1 carbón como combustible, se emite un dirium. Se aconseja ingresar carbón, acero y titanio en diferentes bandas para evitar obstrucciones. -block.coalpurifier.name = Extractor de carbón -block.coalpurifier.fulldescription = Un bloque extractor básico. Salidas de carbón cuando se suministra con grandes cantidades de agua y piedra. -block.titaniumpurifier.name = extractor de titanio -block.titaniumpurifier.fulldescription = Un bloque extractor estándar. Salidas de titanio cuando se suministra con grandes cantidades de agua y hierro. -block.oilrefinery.name = Refinería de petróleo -block.oilrefinery.fulldescription = Refina grandes cantidades de aceite en artículos de carbón. Útil para alimentar torretas a base de carbón cuando las vetas de carbón son escasas. -block.stoneformer.name = Piedra antigua -block.stoneformer.fulldescription = Se vende lava líquida en piedra. Útil para producir cantidades masivas de piedra para purificadores de carbón. -block.lavasmelter.name = Fundición de lava -block.lavasmelter.fulldescription = Utiliza lava para convertir el hierro en acero. Una alternativa a las fundiciones. Útil en situaciones donde el carbón es escaso. -block.stonedrill.name = Perforadora de piedra -block.stonedrill.fulldescription = El taladro esencial. Cuando se coloca en baldosas de piedra, las impresiones de piedra a un ritmo lento de forma indefinida. -block.irondrill.name = Perforadora de hierro -block.irondrill.fulldescription = Un ejercicio básico. Cuando se coloca sobre baldosas de mineral de hierro, emite hierro a un ritmo lento indefinidamente. -block.coaldrill.name = Perforadora de carbón -block.coaldrill.fulldescription = Un ejercicio básico. Cuando se coloca en las baldosas de mineral de carbón, emite carbón a un ritmo lento indefinidamente. -block.uraniumdrill.name = Taladro de uranio -block.uraniumdrill.fulldescription = Un taladro avanzado. Cuando se coloca en placas de mineral de uranio, emite uranio a un ritmo lento de forma indefinida. -block.titaniumdrill.name = Taladro de titanio -block.titaniumdrill.fulldescription = Un taladro avanzado. Cuando se coloca en baldosas de mineral de titanio, emite titanio a un ritmo lento indefinidamente. -block.omnidrill.name = omnidrill -block.omnidrill.fulldescription = El último ejercicio Va a extraer cualquier mineral que se coloca a un ritmo rápido. -block.coalgenerator.name = Generador de carbón -block.coalgenerator.fulldescription = El generador esencial. Genera energía del carbón Emite energía como láser en sus 4 lados. -block.thermalgenerator.name = Generador térmico -block.thermalgenerator.fulldescription = Genera energía de la lava Emite energía como láser en sus 4 lados. -block.combustiongenerator.name = Generador de combustión -block.combustiongenerator.fulldescription = Genera energía del petróleo. Emite energía como láser en sus 4 lados. -block.rtgenerator.name = Generador de RTG -block.rtgenerator.fulldescription = Genera pequeñas cantidades de energía a partir de la desintegración radiactiva del uranio. Emite energía como láser en sus 4 lados. -block.nuclearreactor.name = Reactor nuclear -block.nuclearreactor.fulldescription = Una versión avanzada del generador RTG y el último generador de energía. Genera energía del uranio. Requiere enfriamiento constante de agua. Altamente volátil; explotará violentamente si se suministran cantidades insuficientes de refrigerante. -block.turret.name = Torre -block.turret.fulldescription = Una torrecilla básica y barata. Utiliza piedra para munición. Tiene un poco más de alcance que la torre doble. -block.doubleturret.name = Doble torreta -block.doubleturret.fulldescription = Una versión un poco más poderosa de la torreta. Utiliza piedra para munición. Hace mucho más daño, pero tiene un rango menor. Dispara dos balas. -block.machineturret.name = Torreta de gatling -block.machineturret.fulldescription = Una torreta versátil estándar. Utiliza hierro para munición. Tiene una velocidad de disparo rápida con un daño decente. -block.shotgunturret.name = Torreta divisoria -block.shotgunturret.fulldescription = Una torreta estándar. Utiliza hierro para munición. Dispara una extensión de 7 balas. Alcance más bajo, pero mayor producción de daños que la torreta de gatling. -block.flameturret.name = Torreta de fuego -block.flameturret.fulldescription = Torreta de corto alcance avanzada. Utiliza carbón para munición. Tiene un rango muy bajo, pero un daño muy alto. Bueno para cuartos cercanos. Recomendado para ser utilizado detrás de las paredes. -block.sniperturret.name = Torreta railgun -block.sniperturret.fulldescription = Torreta de largo alcance avanzada. Utiliza acero para munición. Daño muy alto, pero bajo índice de fuego. Es caro de usar, pero puede colocarse lejos de las líneas enemigas debido a su alcance. -block.mortarturret.name = Torreta antiaérea -block.mortarturret.fulldescription = Torreta avanzada de baja salpicadura de daños por salpicadura. Utiliza carbón para munición. Dispara un aluvión de balas que explotan en metralla. Útil para grandes multitudes de enemigos. -block.laserturret.name = Torreta láser -block.laserturret.fulldescription = Torreta de un solo objetivo avanzado. Utiliza el energia. Buena torre de medio alcance. Objetivo único. Nunca falla -block.waveturret.name = Torreta tesla -block.waveturret.fulldescription = Torreta multi-objetivo avanzada. Utiliza el poder Rango medio. Nunca falla. De Medio a bajo daño, pero puede golpear a varios enemigos simultáneamente con rayos en cadena. -block.plasmaturret.name = Torreta de plasma -block.plasmaturret.fulldescription = Versión altamente avanzada de la torreta de fuego. Utiliza carbón como munición. Daño muy alto, rango bajo a medio. -block.chainturret.name = Torreta de cadena -block.chainturret.fulldescription = La torreta de fuego rápido suprema. Usa uranio como munición. Dispara babosas grandes a una alta cadencia. Rango medio. Se extiende por múltiples bloques. Extremadamente duradero. -block.titancannon.name = Cañón titán -block.titancannon.fulldescription = La torreta de largo alcance suprema. Usa uranio como munición. Dispara grandes proyectiles con daño de área a una cadencia media. De largo alcance. Se extiende por múltiples bloques. Extremadamente duradero. -block.playerspawn.name = Punto de aparición del jugador -block.enemyspawn.name = Generador de enemigos +text.about=Creado por [ROYAL]Anuken [] - [SKY] anukendev@gmail.com [] Originalmente una entrada en el [naranja] GDL [] Metal Monstrosity Jam. Créditos: - SFX hecho con [AMARILLO] bfxr [] - Música hecha por [VERDE] RoccoW [] / encontrado en [lime] FreeMusicArchive.org [] Agradecimientos especiales a: - [coral] MitchellFJN []: extensa prueba de juego y comentarios - [cielo] Luxray5474 []: trabajo wiki, contribuciones de código - [lime] Epowerj []: sistema de compilación de código, icono - Todos los probadores beta en itch.io y Google Play\n +text.credits=Créditos +text.discord=¡Únete al Discord de Mindustry! +text.link.discord.description=La sala oficial del discord de Mindustry +text.link.github.description=Código fuente del juego +text.link.dev-builds.description=Estados en desarrollo inestables +text.link.trello.description=Tablero trello oficial para las características planificadas +text.link.itch.io.description=itch.io és la página con descargas para PC y la versión web +text.link.google-play.description=Listado en la tienda de Google Play +text.link.wiki.description=Wiki oficial de Mindustry +text.linkfail=¡Error al abrir el enlace!\nLa URL ha sido copiada a su portapapeles +text.editor.web=¡La versión web no es compatible con el editor!\nDescargue el juego para usarlo. +text.multiplayer.web=¡Esta versión del juego no admite multijugador!\nPara jugar al modo multijugador desde su navegador, use el enlace "versión de varios jugadores" en la página itch.io. +text.gameover=El núcleo fue destruido. +text.highscore=[YELLOW]¡Nueva mejor puntuación! +text.lasted=Duró hasta la ronda +text.level.highscore=Puntuación màs alta: [accent] +text.level.delete.title=Confirmar Eliminación +text.level.select=Selección de nivel +text.level.mode=Modo de juego: +text.savegame=Guardar Partida +text.loadgame=Cargar Partida +text.joingame=Unirse a una Partida +text.newgame=Nueva Partida +text.quit=Salir +text.about.button=Acerca de +text.name=Nombre +text.players={0} Jugadores en línea +text.players.single={0} jugador en línea +text.server.mismatch=Error de paquete: posible desajuste de la versión cliente / servidor.\n¡Asegúrate de que tú y el anfitrión tengáis la última versión de Mindustry! +text.server.closing=[accent] Cerrando servidor ... +text.server.kicked.kick=¡Has sido expulsado del servidor! +text.server.kicked.invalidPassword=¡Contraseña inválida! +text.server.kicked.clientOutdated=Cliente desactualizado ¡Actualiza tu juego! +text.server.kicked.serverOutdated=Servidor desactualizado ¡Pidele actualizar al anfitrión! +text.server.kicked.banned=Tu entrada está prohibida en este servidor. +text.server.kicked.recentKick=Has sido echado recientemente.\nEspera antes de conectarte de nuevo. +text.server.connected=se ha unido. +text.server.disconnected=se ha desconectado +text.nohost=¡No se puede alojar el servidor en un mapa personalizado! +text.host.info=El botón [acento] host [] aloja un servidor en los puertos [escarlata] 6567 [] y [escarlata] 6568. [] Cualquiera en el mismo [LIGHT_GRAY] wifi o red local [] debería poder ver su servidor en su servidor lista. Si desea que las personas puedan conectarse desde cualquier lugar mediante IP, se requiere [acento] reenvío de puerto []. [LIGHT_GRAY] Nota: Si alguien tiene problemas para conectarse a su juego LAN, asegúrese de haber permitido a Mindustry el acceso a su red local en la configuración de su firewall. +text.join.info=Aquí puede ingresar un servidor [acento] IP [] para conectarse, o descubrir servidores de [acento] red local [] para conectarse. Tanto el modo multijugador LAN como WAN son compatibles. [LIGHT_GRAY] Nota: no hay una lista de servidores global automática; si desea conectarse con alguien por IP, deberá solicitar al host su IP. +text.hostserver=Hostear servidor +text.host=Hostear +text.hosting=[acento] Abriendo servidor ... +text.hosts.refresh=Refrescar +text.hosts.discovering=Descubriendo juegos en LAN +text.server.refreshing=Servidor refrescante +text.hosts.none=[lightgray] ¡No se encontraron juegos LAN! +text.host.invalid=[escarlata] No se puede conectar al host. +text.server.friendlyfire=Fuego amigo +text.trace=Rastro del jugador +text.trace.playername=Nombre del jugador: [acento] {0} +text.trace.ip=IP: [acento] {0} +text.trace.id=ID único: [acento] {0} +text.trace.android=Cliente de Android: [acento] {0} +text.trace.modclient=Cliente personalizado: [acento] {0} +text.trace.totalblocksbroken=Total de bloques rotos: [acento] {0} +text.trace.structureblocksbroken=Bloques de estructura rotos: [acento] {0} +text.trace.lastblockbroken=Último bloque roto: [acento] {0} +text.trace.totalblocksplaced=Total de bloques colocados: [acento] {0} +text.trace.lastblockplaced=Último bloque colocado: [acento] {0} +text.invalidid=ID de cliente no válido Presente un informe del error. +text.server.bans=Baneos +text.server.bans.none=¡No se encontraron jugadores baneados! +text.server.admins=Admins +text.server.admins.none=¡No se encontraron administradores! +text.server.add=Agregar servidor +text.server.delete=¿Seguro que quieres eliminar este servidor? +text.server.hostname=Anfitrión: {0} +text.server.edit=Editar servidor +text.server.outdated=[crimson] ¡Servidor obsoleto! [] +text.server.outdated.client=[carmesí] Cliente desactualizado! [] +text.server.version=[lightgray] Versión: {0} +text.server.custombuild=[amarillo] Creación personalizada +text.confirmban=¿Estás seguro de que quieres prohibir este jugador? +text.confirmunban=¿Estás seguro de que quieres desbloquear a este jugador? +text.confirmadmin=¿Seguro que quieres que este jugador sea un administrador? +text.confirmunadmin=¿Seguro que quieres eliminar el estado de administrador de este reproductor? +text.joingame.title=Unirse a una partida +text.joingame.ip=IP: +text.disconnect=Desconectado. +text.disconnect.data=¡Fallo al cargar datos mundiales! +text.connecting=[accent] Conectando ... +text.connecting.data=[accent] Cargando información del mapa... +text.connectfail=[crimson] Fallo al conectar al servidor: [orange] +text.server.port=Puerto: +text.server.addressinuse=¡Dirección ya en uso! +text.server.invalidport=¡Número de puerto inválido! +text.server.error=[crimson] Error en la creación del servidor: [orange] +text.save.new=Nuevo Guardado +text.save.overwrite=¿Seguro que quieres sobrescribir este juego guardado? +text.overwrite=Sobreescribir +text.save.none=¡No hay juegos guardados! +text.saveload=[accent] Guardando... +text.savefail=¡Error al guardar el juego! +text.save.delete.confirm=¿Estás seguro de que deseas eliminar este guardado? +text.save.delete=Borrar +text.save.export=Exportar guardado +text.save.import.invalid=[orange] ¡Este guardado es inválido! +text.save.import.fail=[crimson] Fallo al importar guardado: [orange] {0} +text.save.export.fail=[crimson] Fallo al exportar guardado: [orange] {0} +text.save.import=Importar Guardado +text.save.newslot=Nombre del guardado: +text.save.rename=Renombrar +text.save.rename.text=Nuevo nombre +text.selectslot=Seleccionar una guardado +text.slot=[accent] Casilla {0} +text.save.corrupted=[orange] ¡Arhivo de guardado corrupto o inválido! +text.empty= +text.on=Encendido +text.off=Apagado +text.save.autosave=Guardado automático: {0} +text.save.map=Mapa: {0} +text.save.wave=Horda: {0} +text.save.difficulty=Dificultad: {0} +text.save.date=Guardado por última vez: {0} +text.confirm=Confirmar +text.delete=Eliiminar +text.ok=OK +text.open=Abrir +text.cancel=Cancelar +text.openlink=Abrir enlace +text.copylink=Copiar link +text.back=Atrás +text.quit.confirm=¿Seguro que quieres salir? +text.changelog.title=Changelog +text.changelog.loading=Obteniendo changelog ... +text.changelog.error.android=[naranja] Tenga en cuenta que el registro de cambios no funciona en Android 4.4 y versiones posteriores. Esto se debe a un error interno de Android. +text.changelog.error=[escarlata] ¡Error al obtener el registro de cambios! Comprueba tu conexión a Internet. +text.changelog.current=[amarillo] [[Versión actual] +text.changelog.latest=[naranja] [[Última versión] +text.loading=[accent] Cargando... +text.wave=[orange] Horda {0} +text.wave.waiting=Horda en {0} +text.waiting=Esperando... +text.enemies={0} Enemigos +text.enemies.single={0} Enemigo +text.loadimage=Cargar imagen +text.saveimage=Guardar imagen +text.editor.badsize=[orange]¡Dimensiones de imagen inválidas![]\nDimensiones de mapa válidas: {0} +text.editor.errorimageload=Error al cargar el archivo de imagen: [orange] {0} +text.editor.errorimagesave=Error al guardar el archivo de imagen: [orange] {0} +text.editor.generate=Generar +text.editor.resize=Cambiar tamaño +text.editor.loadmap=Cargar mapa +text.editor.savemap=Guardar mapa +text.editor.loadimage=Cargar imagen +text.editor.saveimage=Guardar imagen +text.editor.unsaved=[scarlet] ¡Tienes cambios sin guardar! [] ¿Estás seguro de que quieres salir? +text.editor.resizemap=Cambiar el tamaño del mapa +text.editor.mapname=Nombre del mapa +text.editor.overwrite=[acento] ¡Advertencia!\nEsto sobrescribe un mapa existente. +text.editor.selectmap=Seleccione un mapa para cargar: +text.width=Ancho: +text.height=Altura: +text.menu=Menú +text.play=Jugar +text.load=Cargar +text.save=Salvar +text.language.restart=Por favor, reinicie su juego para que la configuración de idioma surta efecto. +text.settings.language=Idioma +text.settings=Ajustes +text.tutorial=Tutorial +text.editor=Editor +text.mapeditor=Editor de Mapas +text.donate=Donar +text.settings.reset=Restablecer los valores predeterminados +text.settings.controls=Controles +text.settings.game=Juego +text.settings.sound=Sonido +text.settings.graphics=Gráficos +text.upgrades=Mejoras +text.purchased=[LIME] Creado! +text.weapons=Armas +text.paused=Pausado +text.info.title=[acento] Información +text.error.title=[carmesí] Se ha producido un error +text.error.crashtitle=Ha ocurrido un error +text.blocks.blockinfo=Información de bloque +text.blocks.powercapacity=Capacidad de energía +text.blocks.powershot=Energía/disparo +text.blocks.size=Tamaño +text.blocks.liquidcapacity=Capacidad de liquido +text.blocks.maxitemssecond=Objetos máximos/segundo +text.blocks.powerrange=Rango de energía +text.blocks.itemcapacity=Capacidad de items +text.blocks.inputliquid=Entrada de líquidos +text.blocks.inputitem=Entrada de ítems +text.blocks.explosive=¡Altamente explosivo! +text.blocks.health=Vida +text.blocks.inaccuracy=Inexactitud +text.blocks.shots=Disparos +text.blocks.inputcapacity=Capacidad de entrada +text.blocks.outputcapacity=Capacidad de salida +setting.difficulty.easy=Fácil +setting.difficulty.normal=Mormal +setting.difficulty.hard=Difícil +setting.difficulty.insane=Insano +setting.difficulty.purge=Purga +setting.difficulty.name=Dificultad: +setting.screenshake.name=Shake de pantalla +setting.indicators.name=Indicador del enemigo +setting.effects.name=Mostrar efectos +setting.sensitivity.name=Sensibilidad del controlador +setting.saveinterval.name=Intervalo de autoguardado +setting.seconds=Segundos +setting.fullscreen.name=Pantalla completa +setting.multithread.name=Multithreading +setting.fps.name=Mostrar fps +setting.vsync.name=VSync +setting.lasers.name=Mostrar láseres de poder +setting.healthbars.name=Mostrar barras de vida de enemigos y jugadores +setting.musicvol.name=Volumen de la música +setting.mutemusic.name=Apagar música +setting.sfxvol.name=Volumen de los efectos de sonido +setting.mutesound.name=Apagar sonidos +map.maze.name=Laberinto +map.fortress.name=Fortaleza +map.sinkhole.name=Sumidero +map.caves.name=Cuevas +map.volcano.name=Volcán +map.caldera.name=Caldera +map.scorch.name=Desierto volcánico +map.desert.name=Desierto +map.island.name=Isla +map.grassland.name=Pastizal +map.tundra.name=Tundra +map.spiral.name=Espiral +map.tutorial.name=Tutorial +text.keybind.title=Vuelva a conectar las llaves +keybind.move_x.name=mover_x +keybind.move_y.name=mover_y +keybind.select.name=Elija +keybind.break.name=Romper +keybind.shoot.name=¡Dispara! +keybind.zoom_hold.name=Enfoque_Mantener +keybind.zoom.name=Enfoquè +keybind.block_info.name=Bloque_informacion +keybind.menu.name=Menú +keybind.pause.name=Pausa +keybind.dash.name=Deslizar +keybind.chat.name=Chat +keybind.player_list.name=Jugadores_lista +keybind.console.name=Console +keybind.rotate_alt.name=Rotacion_alt +keybind.rotate.name=Girar +mode.text.help.title=Descripción de modos +mode.waves.name=Hordas +mode.waves.description=El modo normal. Recursos limitados y las hordas vendrán automáticamente +mode.sandbox.name=Sandbox +mode.sandbox.description=Recursos infinitos y sin temporizador para las olas. +mode.freebuild.name=Construcción libre +mode.freebuild.description=Recursos limitados y sin tiempo definido para las hordas +item.stone.name=Piedra +item.coal.name=Carbón +item.titanium.name=Titanio +item.sand.name=Arena +liquid.water.name=Agua +liquid.lava.name=Lava +liquid.oil.name=Aceite +block.door.name=Puerta +block.door-large.name=Puerta grande +block.conduit.name=Conducto +block.pulseconduit.name=Conducto de pulso +block.liquidrouter.name=Enrutador líquido +block.conveyor.name=Transportador +block.router.name=Enrutador +block.junction.name=Union +block.liquidjunction.name=Unión líquida +block.sorter.name=Clasificador +block.smelter.name=horno de fundición +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.name=Thorium +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index 6c8a007520..4d29faf7f7 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -1,528 +1,495 @@ -text.about = Créé par [ROYAL]Anuken.[]\nA l'origine une entrée dans le [orange]GDL[] MM Jam.\n\nCrédits: \n- SFX réalisé avec [yellow]bfxr[] \n- Musique faite par [lime]RoccoW[] / trouvé sur [lime]FreeMusicArchive.org[] \n\nRemerciements particuliers à:\n- [coral]MitchellFJN[]: nombreux tests et retours d'expérience \n- [sky]Luxray5474[]: travail wiki, contributions de code \n- [lime]Epowerj[]: système de compilation de code, icône \n- Tous les beta testeurs sont sur itch.io et Google Play\n -text.discord = Rejoignez le discord de Mindustry -text.changes = [SCARLET]Attention![] \nCertains mécanismes importants du jeu ont ete modifies.\n-Les [accent]telporteurs[] utilisent maintenant de l'énergie.\n-Les [accent]fonderies[] et les[accent]crucibles[] ont maintenant une capacité maximale d'articles.\n-Les [accent]crucibles[] exigent maintenant du charbon comme combustible. -text.gameover = Le noyau a été détruit. -text.highscore = [YELLOW]Nouveau meilleur score! -text.lasted = Vous avez duré jusqu'à la vague -text.level.highscore = Meilleur score: [accent]{0} -text.level.delete.title = Confirmer -text.level.delete = Êtes-vous sûr de vouloir supprimer la carte \"[orange] \"? -text.level.select = Sélection de niveau -text.level.mode = Mode de jeu : -text.savegame = Sauvegarder la partie -text.loadgame = Charger la partie -text.joingame = Rejoindre la partie -text.quit = Quitter -text.about.button = À propos -text.name = Nom : -text.public = Publique -text.players = joueurs en ligne -text.server.player.host = Héberger -text.players.single = joueur en ligne -text.server.mismatch = Erreur de paquet: possible incompatibilité de version client/serveur. Assurez-vous que vous et l'hôte avez la dernière version de Mindustry! -text.server.closing = [accent]Fermeture du serveur ... -text.server.kicked.kick = Vous avez été expulsé du serveur! -text.server.kicked.invalidPassword = Mot de passe non valide ! -text.server.kicked.clientOutdated = Client dépassé! Mettez à jour votre jeu! -text.server.kicked.serverOutdated = Serveur dépassé! Demandez à l'hôte de le mettre à jour! -text.server.kicked.banned = Vous êtes banni sur ce serveur. -text.server.connected = a rejoint le serveur -text.server.disconnected = {0} s'est déconnecté. -text.nohost = Impossible d'héberger le serveur sur une carte personnalisée! -text.hostserver = Héberger un serveur -text.host = Héberger -text.hosting = [accent]Ouverture du serveur ... -text.hosts.refresh = Actualiser -text.hosts.discovering = Recherche de parties LAN -text.server.refreshing = Actualisation du serveur -text.hosts.none = [lightgray]Aucun jeu LAN trouvé! -text.host.invalid = [scarlet]Impossible de se connecter à l'hôte. -text.server.friendlyfire = Tir allié -text.trace = suivre le joueur -text.trace.playername = Nom du joueur: [accent] {0} -text.trace.ip = IP: [accent] {0} -text.trace.id = ID unique: [accent] {0} -text.trace.android = Client Android: [accent] {0} -text.trace.modclient = Client personnalisé: [accent] {0} -text.trace.totalblocksbroken = Total des blocs détruits: [accent] {0} -text.trace.structureblocksbroken = Blocs de structure détruits: [accent] {0} -text.trace.lastblockbroken = Dernier bloc détruit: [accent] {0} -text.trace.totalblocksplaced = Nombre total de blocs placés: [accent] {0} -text.trace.lastblockplaced = Dernier bloc placé: [accent] {0} -text.invalidid = ID client invalide! Soumettre un rapport de bug -text.server.bans = Interdictions -text.server.bans.none = Aucun joueur banni trouvé! -text.server.admins = Administrateurs -text.server.admins.none = Aucun administrateur trouvé! -text.server.add = Ajouter un serveur -text.server.delete = Êtes-vous sûr de vouloir supprimer ce serveur? -text.server.hostname = Héberger -text.server.edit = éditer le serveur -text.server.outdated = [crimson]Serveur obsolète![] -text.server.outdated.client = [Crimson]Client obsolète![] -text.server.version = [lightgray]Version: {0} -text.server.custombuild = [jaune]Construction personnalisée -text.confirmban = Êtes-vous sûr de vouloir bannir ce joueur? -text.confirmunban = Êtes-vous sûr de vouloir annuler le ban de ce joueur? -text.confirmadmin = Êtes-vous sûr de vouloir faire de ce joueur un administrateur? -text.confirmunadmin = Êtes-vous sûr de vouloir supprimer le statut d'administrateur de ce joueur? -text.joingame.byip = Rejoindre par IP ... -text.joingame.title = Rejoindre une partie -text.joingame.ip = IP : -text.disconnect = Déconnecté -text.connecting = [accent]Connexion ... -text.connecting.data = [accent] Chargement des données de la partie ... -text.connectfail = [crimson] Échec de la connexion au serveur : [orange] -text.server.port = Port : -text.server.addressinuse = Adresse déjà utilisée! -text.server.invalidport = Numéro de port incorrect. -text.server.error = [crimson]Erreur lors de l'hébergement du serveur: [orange] {0} -text.tutorial.back = < Précédent\n -text.tutorial.next = Suivant> -text.save.new = Nouvelle sauvegarde -text.save.overwrite = Êtes-vous sûr de vouloir remplacer cette sauvegarde? -text.overwrite = Écraser -text.save.none = Aucune sauvegarde trouvée! -text.saveload = [accent]Sauvegarde ... -text.savefail = Échec de la sauvegarde du jeu ! -text.save.delete.confirm = Êtes-vous sûr de vouloir supprimer cette sauvegarde? -text.save.delete = Supprimer -text.save.export = Exporter la sauvegarde -text.save.import.invalid = [orange]Cette sauvegarde est invalide! -text.save.import.fail = [crimson]Echec de l'importation de la sauvegarde: [orange] {0} -text.save.export.fail = [crimson]Échec de l'exportation de la sauvegarde: [orange] {0} -text.save.import = Importer la sauvegarde -text.save.newslot = Enregistrer le nom: -text.save.rename = Renommer -text.save.rename.text = Nouveau nom: -text.selectslot = Sélectionnez une sauvegarde. -text.slot = [accent]Emplacement {0} -text.save.corrupted = [orange]Le fichier enregistrer est corrompu ou invalide! -text.empty = -text.on = Allumer -text.off = Eteint -text.save.autosave = Sauvegarde automatique -text.save.map = Carte -text.save.wave = Vague : -text.save.difficulty = DIFFICULTÉ -text.save.date = Dernière sauvegarde: {0} -text.confirm = Confirmer -text.delete = Supprimer -text.ok = OK -text.open = Ouvrir -text.cancel = Annuler -text.openlink = Lien public -text.back = Retour -text.quit.confirm = Êtes-vous sûr de vouloir quitter? -text.changelog.title = Note de mise à jour -text.changelog.error = [Scarlet] Erreur lors de l'obtention du changement de serveur! Vérifiez votre connexion internet. -text.changelog.current = [jaune] [[Version actuelle] -text.changelog.latest = [orange][[Dernière version] -text.loading = [accent]Chargement ... -text.wave = [orange]Vague {0} -text.wave.waiting = Vague dans {0} -text.waiting = Attente... -text.enemies = ennemis -text.enemies.single = Ennemi -text.loadimage = Charger l'image -text.saveimage = Enregistrer l'image -text.oregen = Génération de minerais -text.editor.badsize = [orange]Dimensions de l'image non valides![] Dimensions de la carte valides: {0} -text.editor.errorimageload = Erreur lors du chargement du fichier image:[orange] {0} -text.editor.errorimagesave = Erreur lors de la sauvegarde du fichier image:[orange] {0} -text.editor.generate = Générer -text.editor.resize = Redimensionner -text.editor.loadmap = Charger la carte -text.editor.savemap = Enregistrer la carte -text.editor.loadimage = Charger l'image -text.editor.saveimage = Enregistrer l'image -text.editor.unsaved = [scarlet] Vous avez des changements non sauvegardés![] Êtes-vous sûr de vouloir quitter? -text.editor.brushsize = Taille de la brosse: -text.editor.noplayerspawn = Cette carte n'a pas de point d'apparition de joueur! -text.editor.manyplayerspawns = Les cartes ne peuvent pas avoir plus d'un point d'apparition de joueur! -text.editor.manyenemyspawns = Il ne peut pas avoir plus de {0} points d'apparition ennemis! -text.editor.resizemap = Redimensionner la carte -text.editor.resizebig = [scarlet]Attention![] Les cartes de plus de 256 unités peuvent laggés et être instables. -text.editor.mapname = Nom de la carte: -text.editor.overwrite = [accent]Attention! Cela écrasera la carte existante. -text.editor.failoverwrite = [Crimson]Impossible d'écraser la carte par défaut! -text.editor.selectmap = Sélectionnez une carte à charger: -text.width = Largeur: -text.height = Hauteur: -text.randomize = Rendre aléatoire -text.apply = Appliquer -text.update = Modifier -text.menu = Menu -text.play = Jouer -text.load = Charger -text.save = Sauvegarder -text.language.restart = Veuillez redémarrer votre jeu pour que les paramètres de langue soient appliqués. -text.settings.language = Langue -text.settings = Réglages -text.tutorial = Tutoriel -text.editor = Éditeur -text.mapeditor = Éditeur de carte -text.donate = Faire un don -text.settings.reset = Valeur par défaut. -text.settings.controls = Contrôles -text.settings.game = Jeu -text.settings.sound = Son -text.settings.graphics = Graphique -text.upgrades = Améliorations -text.purchased = [VERT]Créé! -text.weapons = Armes -text.paused = Pause -text.respawn = Réapparition dans -text.info.title = [accent]Info -text.error.title = [crimson]Une erreur est survenue -text.error.crashmessage = [SCARLET]Une erreur inattendue est survenue, et aurait provoqué un crash.[] Veuillez indiquer les circonstances exactes dans lesquelles cette erreur est survenue au développeur:[ORANGE] anukendev@gmail.com[] -text.error.crashtitle = Une erreur est survenue -text.mode.break = Mode de rupture: {0} -text.mode.place = Placez le mode: {0} -placemode.hold.name = Ligne -placemode.areadelete.name = surface -placemode.touchdelete.name = toucher -placemode.holddelete.name = tenir -placemode.none.name = aucun -placemode.touch.name = toucher -placemode.cursor.name = curseur -text.blocks.extrainfo = [accent] info supplémentaire du bloc: -text.blocks.blockinfo = Bloquer les infos -text.blocks.powercapacity = capacité d'énergie -text.blocks.powershot = Energie/Tir -text.blocks.powersecond = Energie/Seconde -text.blocks.powerdraindamage = Utilisation d'énergie/Dommage -text.blocks.shieldradius = rayon du bouclier -text.blocks.itemspeedsecond = Vitesse d'Article/Seconde -text.blocks.range = Portée -text.blocks.size = Taille -text.blocks.powerliquid = énergie/Liquide -text.blocks.maxliquidsecond = Max Liquide/Seconde -text.blocks.liquidcapacity = Capacité liquide -text.blocks.liquidsecond = Liquide/seconde -text.blocks.damageshot = Dégâts/tir -text.blocks.ammocapacity = Capacité de munitions -text.blocks.ammo = Munition -text.blocks.ammoitem = Munitions/Article -text.blocks.maxitemssecond = Max articles/seconde -text.blocks.powerrange = Gamme de puissance -text.blocks.lasertilerange = portée du laser -text.blocks.capacity = Capacité -text.blocks.itemcapacity = Capacité article -text.blocks.maxpowergenerationsecond = Génération max d'énergie/seconde -text.blocks.powergenerationsecond = Génération d'énergie/seconde -text.blocks.generationsecondsitem = Génération Secondes / item -text.blocks.input = entrée -text.blocks.inputliquid = Entrée de liquide -text.blocks.inputitem = entré d'article -text.blocks.output = Sortie -text.blocks.secondsitem = Secondes/article -text.blocks.maxpowertransfersecond = Transfert max d'énergie/seconde -text.blocks.explosive = Hautement explosif ! -text.blocks.repairssecond = Réparation/seconde -text.blocks.health = Santé -text.blocks.inaccuracy = Inexactitude -text.blocks.shots = tirs -text.blocks.shotssecond = Tirs/seconde -text.blocks.fuel = Carburant -text.blocks.fuelduration = Durée du carburant -text.blocks.maxoutputsecond = Sortie max/seconde -text.blocks.inputcapacity = Capacité d'entrée -text.blocks.outputcapacity = Capacité de sortie -text.blocks.poweritem = Energie/Article -text.placemode = Mode Placement -text.breakmode = Mode destruction -text.health = santé -setting.difficulty.easy = facile -setting.difficulty.normal = normal -setting.difficulty.hard = difficile -setting.difficulty.insane = Extreme -setting.difficulty.purge = Purge -setting.difficulty.name = Difficulté: -setting.screenshake.name = Tremblement d'écran -setting.smoothcam.name = Caméra lisse -setting.indicators.name = Indicateurs ennemis -setting.effects.name = Effets d'affichage -setting.sensitivity.name = Sensibilité de la manette -setting.saveinterval.name = Intervalle des sauvegardes auto -setting.seconds = {0} secondes -setting.fullscreen.name = Plein écran -setting.multithread.name = Multithreading [scarlet] (instable!) -setting.fps.name = Afficher FPS -setting.vsync.name = VSync -setting.lasers.name = Afficher les rayons des lasers -setting.healthbars.name = Afficher les barres de santé des entités -setting.pixelate.name = Pixéliser l'écran -setting.musicvol.name = volume musique -setting.mutemusic.name = Musique muette -setting.sfxvol.name = Volume SFX -setting.mutesound.name = Son muet -map.maze.name = Labyrinthe -map.fortress.name = forteresse -map.sinkhole.name = gouffre -map.caves.name = cavernes -map.volcano.name = volcan -map.caldera.name = chaudron -map.scorch.name = brûlure -map.desert.name = désert -map.island.name = Île -map.grassland.name = prairie -map.tundra.name = toundra -map.spiral.name = spirale -map.tutorial.name = tutoriel -tutorial.intro.text = [yellow]Bienvenue dans le tutoriel[]. Pour commencer, appuyez sur \"suivant\". -tutorial.moveDesktop.text = Pour vous déplacer, utilisez les touches [orange][[WASD][]. Maintenez [orange]shift[] pour accélérer. Maintenez la touche [orange]CTRL[] enfoncée tout en utilisant la [orange]molette[] pour effectuer un zoom avant ou arrière. -tutorial.shoot.text = Utilisez votre souris pour viser, maintenez le [orange]bouton gauche de la souris[] pour tirer. Essayez de pratiquer sur la [yellow]cible[]. -tutorial.moveAndroid.text = Pour déplacer votre vue, faites glisser un doigt sur l'écran. Pincez et faites glisser pour effectuer un zoom avant ou arrière. -tutorial.placeSelect.text = Essayez de sélectionner un [yellow]transporteur[] dans le menu des blocs en bas à droite. -tutorial.placeConveyorDesktop.text = Utilisez la [orange][[molette][] pour faire pivoter le transporteur [orange]vers l'avant[], puis placez-le dans l'emplacement [yellow]marqué[] en utilisant le [orange][[bouton gauche de la souris][]. -tutorial.placeConveyorAndroid.text = Utilisez [orange][[bouton de rotation][] pour faire pivoter le transporteur [orange]vers l'avant[], faites-le glisser avec votre doigt, puis placez-le dans l'emplacement [yellow]marqué[] avec [orange][[coche][]. -tutorial.placeConveyorAndroidInfo.text = Vous pouvez également appuyer sur l'icône du réticule en bas à gauche pour passer en [orange][[mode tactile][] et placer des blocs en appuyant sur l'écran. En mode tactile, les blocs peuvent être pivotés avec la flèche en bas à gauche. Appuyez sur [yellow]suivant[] pour essayer. -tutorial.placeDrill.text = Maintenant, sélectionnez et placez un [yellow]extracteur de pierre[] à l'endroit marqué. -tutorial.blockInfo.text = Si vous voulez en savoir plus sur un bloc, vous pouvez appuyer sur le [orange]point d'interrogation[] en haut à droite pour lire sa description. -tutorial.deselectDesktop.text = Vous pouvez désélectionner un bloc en utilisant le [orange][[bouton droit de la souris][]. -tutorial.deselectAndroid.text = Vous pouvez désélectionner un bloc en appuyant sur le bouton [orange]X[]. -tutorial.drillPlaced.text = L'extracteur produira maintenant de la [yellow]pierre[], qui sera placée sur le transporteur, puis sera emmenée dans le [yellow]noyau[]. -tutorial.drillInfo.text = Différents minerais ont besoin de différents extracteurs. La pierre nécessite des extracteurs de pierre, le fer des extracteurs de fer,...etc... -tutorial.drillPlaced2.text = Le déplacement d'article dans le noyau le place dans votre[yellow]inventaire[], au milieu à droite. Le placement de blocs utilise les éléments de votre inventaire. -tutorial.moreDrills.text = Vous pouvez relier plusieurs extracteurs et transporteurs ensemble, comme ça. -tutorial.deleteBlock.text = Vous pouvez supprimer des blocs en cliquant sur le clique [orange]droit de la souris[] sur le bloc que vous voulez supprimer. Essayez de supprimer ce transporteur. -tutorial.deleteBlockAndroid.text = Vous pouvez supprimer des blocs en [orange]sélectionnant le réticule[] dans [orange] le menu du mode destruction[] en bas à gauche et en appuyant sur un bloc. Essayez de supprimer ce transporteur. -tutorial.placeTurret.text = Maintenant, sélectionnez et placez une [yellow]tourelle[] à l'[yellow]emplacement marqué[]. -tutorial.placedTurretAmmo.text = Cette tourelle accepte maintenant les [yellow]munitions[] du transporteur. Vous pouvez voir combien de munitions elle a en la survolant et en vérifiant sa [green]barre verte[]. -tutorial.turretExplanation.text = Les tourelles tirent automatiquement sur l'ennemi le plus proche, pourvu qu'elles aient suffisamment de munitions. -tutorial.waves.text = Toutes les [yellow]60 secondes[], une [coral]vague d'ennemis[] apparaîtra dans des endroits spécifiques et tentera de détruire votre noyau. -tutorial.coreDestruction.text = Votre objectif est de [yellow]défendre le noyau[]. Si le noyau est détruit, vous [coral]perdez le jeu[]. -tutorial.pausingDesktop.text = Si vous avez besoin de faire une pause, appuyez sur le bouton [orange]pause[] en haut à gauche pour mettre le jeu en pause. Vous pouvez toujours casser et placer des blocs en pause, mais vous ne pouvez pas bouger ou tirer. -tutorial.pausingAndroid.text = Si vous avez besoin de faire une pause, appuyez sur le bouton [orange]pause[] en haut à gauche pour mettre le jeu en pause. Vous pouvez toujours casser et placer des blocs en pause. -tutorial.purchaseWeapons.text = Vous pouvez acheter de nouvelles [yellow]armes[] pour votre robot en ouvrant le menu de mise à niveau en bas à gauche. -tutorial.switchWeapons.text = Changez d'arme en cliquant sur l'icône en bas à droite, ou en utilisant les chiffres [orange][[1-9][]. -tutorial.spawnWave.text = Une vague arrive. Détruisez-les. -tutorial.pumpDesc.text = Dans les vagues plus lointaines, vous devrez peut-être utiliser des [yellow]pompes[] pour distribuer du liquide pour les générateurs ou les extracteurs. -tutorial.pumpPlace.text = Les pompes fonctionnent de la même manière que les extracteurs, sauf qu'elles récoltent du liquides et non du minerai. Essayez de placer une pompe sur [yellow]pétrole[] désigné. -tutorial.conduitUse.text = Maintenant, placez un [orange]conduit[] qui s'éloigne de la pompe. -tutorial.conduitUse2.text = Et un autre ... -tutorial.conduitUse3.text = Et un autre ... -tutorial.generator.text = Maintenant, placez un bloc [orange]de générateur à combustion[] à l'extrémité du conduit. -tutorial.generatorExplain.text = Ce générateur va maintenant créer de l' [yellow]énergie[] à partir de pétrole. -tutorial.lasers.text = L'énergie est distribuée à l'aide de [yellow]lasers d'énergie[]. Tournez et placez-en un ici. -tutorial.laserExplain.text = Le générateur va maintenant déplacer la puissance dans le laser. Un faisceau [yellow]opaque[] signifie qu'il transmet actuellement de la puissance, et un faisceau [yellow]transparent[] signifie que ce n'est pas le cas. -tutorial.laserMore.text = Vous pouvez vérifier la puissance d'un bloc en survolant celui-ci et en vérifiant la [yellow]barre jaune[] en haut. -tutorial.healingTurret.text = Ce laser peut être utilisé pour alimenter une [lime]tourelle de réparation[]. Placez-en une ici. -tutorial.healingTurretExplain.text = Tant qu'elle a de la puissance, cette tourelle [lime]réparera les blocs voisins[].En jouant, assurez-vous d'en avoir une dans votre base le plus rapidement possible! -tutorial.smeltery.text = De nombreux blocs nécessitent de l' [orange]acier[] pour fabriquer, ce qui nécessite une [orange]fonderie[]. Placez-en une ici. -tutorial.smelterySetup.text = Cette fonderie produira maintenant de l' [orange]acier[] à partir du fer, utilisant le charbon comme combustible. -tutorial.tunnelExplain.text = Notez également que les objets traversent un [orange]tunnel[] et émergent de l'autre côté, traversant le bloc de pierre. Gardez à l'esprit que les tunnels ne peuvent traverser que 2 blocs. -tutorial.end.text = Et cela conclut le tutoriel! Bonne chance! -text.keybind.title = Relier le clés -keybind.move_x.name = mouvement x -keybind.move_y.name = mouvement y -keybind.select.name = sélectionner -keybind.break.name = Pause -keybind.shoot.name = tirer -keybind.zoom_hold.name = tenir le zoom -keybind.zoom.name = zoom -keybind.block_info.name = bloc_info -keybind.menu.name = menu -keybind.pause.name = Pause -keybind.dash.name = attaque frontal -keybind.chat.name = chat -keybind.player_list.name = Liste des joueurs -keybind.console.name = console -keybind.rotate_alt.name = tourner_alt -keybind.rotate.name = Tourner -keybind.weapon_1.name = Arme 1 -keybind.weapon_2.name = Arme 2 -keybind.weapon_3.name = Arme 3 -keybind.weapon_4.name = Arme 4 -keybind.weapon_5.name = Arme 5 -keybind.weapon_6.name = Arme 6 -mode.waves.name = Vagues -mode.sandbox.name = bac à sable -mode.freebuild.name = construction libre -upgrade.standard.name = La norme -upgrade.standard.description = Le robot standard. -upgrade.blaster.name = blaster -upgrade.blaster.description = Tire faiblement et lentetement. -upgrade.triblaster.name = Tri-blaster -upgrade.triblaster.description = Tire 3 balles se propageant en V. -upgrade.clustergun.name = clustergun -upgrade.clustergun.description = Tire une portée de grenades explosives. -upgrade.beam.name = beam cannon -upgrade.beam.description = Tire un rayon laser de perçage à longue portée. -upgrade.vulcan.name = Vulcain -upgrade.vulcan.description = Tire un barrage de balles rapides. -upgrade.shockgun.name = shockgun -upgrade.shockgun.description = Tire une charge de balles qui explosent en éclats. -item.stone.name = pierre -item.iron.name = fer -item.coal.name = charbon -item.steel.name = Acier -item.titanium.name = Titane -item.dirium.name = dirium -item.uranium.name = uranium -item.sand.name = sable -liquid.water.name = eau -liquid.plasma.name = plasma -liquid.lava.name = lave -liquid.oil.name = pétrole -block.weaponfactory.name = usine d'armes -block.weaponfactory.fulldescription = Utilisé pour créer des armes pour le joueur robot. Cliquez pour utiliser. Extrait automatiquement les ressources du noyau. -block.air.name = air -block.blockpart.name = partie de block -block.deepwater.name = eaux profondes -block.water.name = eau -block.lava.name = lave -block.oil.name = pétrole -block.stone.name = pierre -block.blackstone.name = pierre noire -block.iron.name = fer -block.coal.name = charbon -block.titanium.name = titane -block.uranium.name = uranium -block.dirt.name = terre -block.sand.name = sable -block.ice.name = glace -block.snow.name = neige -block.grass.name = herbe -block.sandblock.name = bloc de sable -block.snowblock.name = bloc de neige -block.stoneblock.name = bloc de pierre -block.blackstoneblock.name = bloc de roche noire -block.grassblock.name = bloc d'herbe -block.mossblock.name = bloc de mousse -block.shrub.name = arbuste -block.rock.name = roche -block.icerock.name = roche de glace -block.blackrock.name = roche noire -block.dirtblock.name = bloc de terre -block.stonewall.name = mur de pierres -block.stonewall.fulldescription = Un bloc défensif bon marché. Utile pour protéger le noyau et les tourelles durant les premières vagues. -block.ironwall.name = mur de fer -block.ironwall.fulldescription = Un bloc défensif de base. Fournit une protection contre les ennemis. -block.steelwall.name = mur en acier -block.steelwall.fulldescription = Un bloc défensif standard. une protection adéquate contre les ennemis. -block.titaniumwall.name = mur de titane -block.titaniumwall.fulldescription = Un bloc défensif très résistant. Fournit une protection contre les ennemis. -block.duriumwall.name = mur de dirium -block.duriumwall.fulldescription = Un bloc défensif extrêmement résistant. Fournit une protection contre les ennemis. -block.compositewall.name = mur composite -block.steelwall-large.name = grand mur d'acier -block.steelwall-large.fulldescription = Un bloc défensif standard, prend plusieurs blocs de largeurs. -block.titaniumwall-large.name = grand mur de titane -block.titaniumwall-large.fulldescription = Un bloc défensif très résistant, prend plusieurs blocs de largeurs. -block.duriumwall-large.name = grand mur de dirium -block.duriumwall-large.fulldescription = Un bloc défensif extrêmement résistant, prend plusieurs blocs de largeurs. -block.titaniumshieldwall.name = mur blindé -block.titaniumshieldwall.fulldescription = Un bloc défensif solide, avec un bouclier intégré. Nécessite de l'énergie. Utilise l'énergie pour absorber les balles ennemies. Il est recommandé d'utiliser un distributeur d'énergie pour fournir de l'énergie à ce bloc. -block.repairturret.name = tourelle de réparation -block.repairturret.fulldescription = Répare les blocs avoisinants endommagés dans un zone circulaire à un rythme lent. Utilise de l'énergie. -block.megarepairturret.name = tourelle de réparation II -block.megarepairturret.fulldescription = Répare les blocs avoisinants endommagés dans un zone circulaire à un rythme régulier. Utilise de l'énergie. -block.shieldgenerator.name = générateur de bouclier -block.shieldgenerator.fulldescription = Un bloc défensif avancé. Protège tous les blocs avoisinants dans une zone circulaire. Utilise l'énergie à un rythme lent, mais draine beaucoup d'énergie au contact d'un tir ennemi. -block.door.name = porte -block.door.fulldescription = Un bloc qui peut être ouvert et fermé en cliquant dessus. -block.door-large.name = grande porte -block.door-large.fulldescription = Un bloc qui peut être ouvert et fermé en cliquant dessus. -block.conduit.name = conduit -block.conduit.fulldescription = Bloc de transport de liquide basique. Fonctionne comme un transporteur, mais avec des liquides. A placé à coté de pompes. Peut être utilisé comme un pont sur les liquides pour les ennemis et les joueurs. -block.pulseconduit.name = conduit à impulsion -block.pulseconduit.fulldescription = Bloc de transport de liquide avancé. Transporte les liquides plus rapidement et stocke plus que les conduits standards. -block.liquidrouter.name = routeur de liquide -block.liquidrouter.fulldescription = Fonctionne de manière similaire à un routeur. Accepte l'entrée de liquide d'un côté et l'envoie vers 3 autres côtés. Utile pour répartir le liquide d'un conduit vers plusieurs autres conduits. -block.conveyor.name = transporteur -block.conveyor.fulldescription = Bloc de transport standard. Déplace les objets vers l'avant et les dépose automatiquement dans les tourelles ou des blocs d'artisanats. Rotatif. Peut être utilisé comme une plateforme sur les liquides, pour les ennemis et les joueurs. -block.steelconveyor.name = transporteur en acier -block.steelconveyor.fulldescription = transporteur d'articles avancé. Déplace les objets plus rapidement que les transporteurs standards. -block.poweredconveyor.name = transporteur à impulsions -block.poweredconveyor.fulldescription = Le transporteur d'articles ultime. Déplace les articles plus rapidement que les convoyeurs en acier. -block.router.name = Routeur -block.router.fulldescription = Accepte les éléments d'une direction et les distribue dans 3 autres directions. Peut également stocker une certaine quantité d'articles. Utile pour diviser cette quantité afin d'approvisionner plusieurs tourelles ou des blocs d'artisanat. -block.junction.name = jonction -block.junction.fulldescription = Agit comme un pont pour deux transporteurs qui se croisent et qui possèdent différents articles. -block.conveyortunnel.name = tunnel de transport -block.conveyortunnel.fulldescription = Transporte des articles sous les blocs. Pour l'utiliser, placez les entre des blocs, au maximum deux. Assurez-vous que les deux tunnels sont orientés dans des directions opposées. -block.liquidjunction.name = jonction à liquide -block.liquidjunction.fulldescription = Agit comme un pont pour deux conduits. Utile dans la situations ou deux conduits se croisent et transportent différents liquides. -block.liquiditemjunction.name = jonction de liquide-article -block.liquiditemjunction.fulldescription = Agit comme un pont pour croiser les conduits et les convoyeurs. -block.powerbooster.name = distributeur d'énergie -block.powerbooster.fulldescription = Distribue la puissance à tous les blocs avoisinants dans une zone circulaire. -block.powerlaser.name = laser d'énergie -block.powerlaser.fulldescription = Crée un laser qui transmet la puissance au bloc en face de lui. Ne génère pas d'énergie par lui-même. Idéal avec des générateurs ou d'autres lasers. -block.powerlaserrouter.name = routeur laser -block.powerlaserrouter.fulldescription = Laser qui distribue la puissance à trois directions à la fois. Utile pour séparer l'énergie afin d'alimenter plusieurs blocs -block.powerlasercorner.name = laser en angle droit -block.powerlasercorner.fulldescription = Laser qui distribue la puissance à deux directions en angle droit. Utile pour séparer l'énergie afin d'alimenter plusieurs blocs. -block.teleporter.name = téléporteur -block.teleporter.fulldescription = Bloc de transport avancé. Les téléporteurs saisissent des articles aux autres téléporteurs de la même couleur. Ne fait rien si aucun téléporteur de la même couleur n'existe. Si plusieurs téléporteurs existent de la même couleur, un téléporteur aléatoire est sélectionné. Utilise de l'énergie. Cliquez pour changer de couleur. -block.sorter.name = trieur -block.sorter.fulldescription = Trie l'article par type de matériau. Le matériau à accepter est indiqué par la couleur du bloc. Tous les éléments qui correspondent au matériau de tri sont sortis vers l'avant, tout le reste est sorti à gauche et à droite. -block.core.name = noyau -block.pump.name = pompe -block.pump.fulldescription = Pompe les liquides provenant d'un bloc source - généralement de l'eau, de la lave ou de l'huile. Transmet le liquide dans les conduits voisins. -block.fluxpump.name = pompe à flux -block.fluxpump.fulldescription = Une version avancée de la pompe. Stocke plus et pompe le liquide plus rapidement que la pompe ordinaire. -block.smelter.name = fonderie -block.smelter.fulldescription = Le bloc d'artisanat essentiel. Produit de l'acier lorsqu'il est approvisionné en fer et charbon. Il est conseillé d'introduire le fer et le charbon par différents transporteurs pour éviter les situations de débordement. -block.crucible.name = Crucible -block.crucible.fulldescription = Un bloc d'artisanat avancé. Produit du diridium lorsqu'il est approvisionné en fer, en titanium et en charbon . Il est conseillé d'introduire ces minerais par différents transporteurs. -block.coalpurifier.name = raffinerie de charbon -block.coalpurifier.fulldescription = Un bloc d'artisanat de base. Produit du charbon lorsqu'il est fourni avec de grandes quantités d'eau et de pierre. -block.titaniumpurifier.name = raffinerie de titane -block.titaniumpurifier.fulldescription = Un bloc d'artisanat avancé. Produit du titane lorsqu'il est fourni avec de grandes quantités d'eau et de fer. -block.oilrefinery.name = raffinerie de pétrole -block.oilrefinery.fulldescription = Un bloc d'artisanat standard. Affine de grandes quantités de pétrole grâce au charbon. Utile pour alimenter les tourelles à charbon lorsque les filons de charbon sont rares. -block.stoneformer.name = raffinerie de pierre -block.stoneformer.fulldescription = Un bloc d'artisanat standard. Il purifie la lave en pierre. Utile pour produire des quantités massives de pierre. -block.lavasmelter.name = fonderie d'acier -block.lavasmelter.fulldescription = Un bloc d'artisanat de base. Utilise la lave pour convertir le fer en acier. Une alternative aux fonderies. Utile dans les situations où le charbon est rare. -block.stonedrill.name = extracteur de pierre -block.stonedrill.fulldescription = L'extracteur essentiel. Lorsqu'il est placé sur de la pierre, il l'extrait à un rythme rapide. -block.irondrill.name = extracteur de fer -block.irondrill.fulldescription = Un extracteur de base. Lorsqu'ils il est placé sur un minerai de charbon, il l'extrait à un rythme régulier. -block.coaldrill.name = extracteur de charbon -block.coaldrill.fulldescription = Un extracteur de base. Lorsqu'il est placé sur un minerai de charbon, il l'extrait à un rythme régulier. -block.uraniumdrill.name = extracteur d'uranium -block.uraniumdrill.fulldescription = Un extracteur avancé .Lorsqu'il est placé sur un minerai d'uranium, il l'extrait lentement. -block.titaniumdrill.name = extracteur de titane -block.titaniumdrill.fulldescription = Un extracteur avancé. Lorsqu'il est placé sur un minerai de titane, il l'extrait lentement. -block.omnidrill.name = omni-extracteur -block.omnidrill.fulldescription = L'extracteur ultime .Minera n'importe quel minerai sur lequel il est placé à un rythme rapide. -block.coalgenerator.name = générateur à charbon -block.coalgenerator.fulldescription = Le générateur essentiel. Génère de l'énergie à partir du charbon. eparpille l'énergie de ses 4 cotés. -block.thermalgenerator.name = générateur thermique -block.thermalgenerator.fulldescription = Génère de l'énergie à partir de la lave. éparpille l'énergie de ses 4 cotés. -block.combustiongenerator.name = générateur à combustion -block.combustiongenerator.fulldescription = Génère de l'énergie à partir du pétrole. éparpille l'énergie de ses 4 cotés. -block.rtgenerator.name = Générateur RTG -block.rtgenerator.fulldescription = Génère de petites quantités d'énergie à partir d'uranium. éparpille l'énergie de ses 4 cotés -block.nuclearreactor.name = réacteur nucléaire -block.nuclearreactor.fulldescription = Une version avancée du générateur RTG ,et le générateur d'énergie ultime. Génère de l'énergie à partir de l'uranium. Nécessite un refroidissement à eau constant. Hautement inflammable; explosera violemment si des quantités insuffisantes de liquide de refroidissement sont fournies. -block.turret.name = tourelle -block.turret.fulldescription = Une tourelle basique et bon marché. Utilise la pierre pour munition. A légèrement plus de portée que la double-tourelle. -block.doubleturret.name = tourelle double -block.doubleturret.fulldescription = Une version légèrement plus puissante de la tourelle. Utilise la pierre comme munition. Fait beaucoup plus de dégâts, mais a une portée inférieure. -block.machineturret.name = tourelle gattling -block.machineturret.fulldescription = Une tourelle complète standard. Utilise le fer pour munition. A une vitesse de tir rapide avec des dégâts décents. -block.shotgunturret.name = tourelle fusil à pompe. -block.shotgunturret.fulldescription = Une tourelle standard. Utilise le fer pour munition. Tire une portée de 7 balles. Portée basse, mais plus de dégâts que la tourelle gattling. -block.flameturret.name = tourelle incendiaire -block.flameturret.fulldescription = Tourelle avancée à courte portée. Utilise du charbon pour munition. A une portée très faible, mais des dégâts très élevés. Bon pour les places étroites. Recommandé pour tirer à travers les murs. -block.sniperturret.name = Tourelle laser -block.sniperturret.fulldescription = Tourelle avancée à longue portée. Utilise l'acier pour munition. Dommages très élevés, mais faible vitesse de tir. Chère, mais peut être placé loin des lignes ennemies en raison de sa portée. -block.mortarturret.name = Tourelle Antiaérienne -block.mortarturret.fulldescription = Tourelle avancée à fragmentation de faible précision. Utilise du charbon pour munition. Tire un barrage de balles qui explose en éclats. Utile pour les grandes foules d'ennemis. -block.laserturret.name = Tourelle Laser -block.laserturret.fulldescription = Tourelle à cible unique avancée. Utilise de l'énergie. Bonne tourelle polyvalente de moyenne portée. Une seule cible seulement. Ne manque jamais. -block.waveturret.name = Tourelle Tesla -block.waveturret.fulldescription = Tourelle multi-cible avancée. Utilise de l'énergie. Portée moyenne. Ne manque jamais sa cible. Peu de dégâts, mais peut frapper plusieurs ennemis simultanément avec sa répétition d'éclair. -block.plasmaturret.name = Tourelle à plasma -block.plasmaturret.fulldescription = Version très avancée de la tourelle incendiaire. Utilise le charbon comme munition. Dommages très élevés, de faible à moyenne portée. -block.chainturret.name = Tourelle à répétition. -block.chainturret.fulldescription = La tourelle ultime à tir rapide. Utilise l'uranium comme munition. Tire de grosses salves à une vitesse de feu élevée. Portée moyenne. Traverse plusieurs carreaux. Extrêmement résistante. -block.titancannon.name = Cannon Titan -block.titancannon.fulldescription = La tourelle à longue portée ultime. Utilise l'uranium comme munition. Tire de gros obus à dégâts de zone à une cadence de tir moyenne. Longue portée. occupe plusieurs blocks. Extrêmement dur. -block.playerspawn.name = point d'apparition joueur -block.enemyspawn.name = Point d'apparition ennemie +text.about=Créé par [ROYAL]Anuken.[]\nA l'origine une entrée dans le [orange]GDL[] MM Jam.\n\nCrédits: \n- SFX réalisé avec [yellow]bfxr[] \n- Musique faite par [lime]RoccoW[] / trouvé sur [lime]FreeMusicArchive.org[] \n\nRemerciements particuliers à:\n- [coral]MitchellFJN[]: nombreux tests et retours d'expérience \n- [sky]Luxray5474[]: travail wiki, contributions de code \n- [lime]Epowerj[]: système de compilation de code, icône \n- Tous les beta testeurs sont sur itch.io et Google Play\n +text.discord=Rejoignez le discord de Mindustry +text.gameover=Le noyau a été détruit. +text.highscore=[YELLOW]Nouveau meilleur score! +text.lasted=Vous avez duré jusqu'à la vague +text.level.highscore=Meilleur score: [accent]{0} +text.level.delete.title=Confirmer +text.level.select=Sélection de niveau +text.level.mode=Mode de jeu : +text.savegame=Sauvegarder la partie +text.loadgame=Charger la partie +text.joingame=Rejoindre la partie +text.quit=Quitter +text.about.button=À propos +text.name=Nom : +text.players=joueurs en ligne +text.players.single=joueur en ligne +text.server.mismatch=Erreur de paquet: possible incompatibilité de version client/serveur. Assurez-vous que vous et l'hôte avez la dernière version de Mindustry! +text.server.closing=[accent]Fermeture du serveur ... +text.server.kicked.kick=Vous avez été expulsé du serveur! +text.server.kicked.invalidPassword=Mot de passe non valide ! +text.server.kicked.clientOutdated=Client dépassé! Mettez à jour votre jeu! +text.server.kicked.serverOutdated=Serveur dépassé! Demandez à l'hôte de le mettre à jour! +text.server.kicked.banned=Vous êtes banni sur ce serveur. +text.server.connected=a rejoint le serveur +text.server.disconnected={0} s'est déconnecté. +text.nohost=Impossible d'héberger le serveur sur une carte personnalisée! +text.hostserver=Héberger un serveur +text.host=Héberger +text.hosting=[accent]Ouverture du serveur ... +text.hosts.refresh=Actualiser +text.hosts.discovering=Recherche de parties LAN +text.server.refreshing=Actualisation du serveur +text.hosts.none=[lightgray]Aucun jeu LAN trouvé! +text.host.invalid=[scarlet]Impossible de se connecter à l'hôte. +text.server.friendlyfire=Tir allié +text.trace=suivre le joueur +text.trace.playername=Nom du joueur: [accent] {0} +text.trace.ip=IP: [accent] {0} +text.trace.id=ID unique: [accent] {0} +text.trace.android=Client Android: [accent] {0} +text.trace.modclient=Client personnalisé: [accent] {0} +text.trace.totalblocksbroken=Total des blocs détruits: [accent] {0} +text.trace.structureblocksbroken=Blocs de structure détruits: [accent] {0} +text.trace.lastblockbroken=Dernier bloc détruit: [accent] {0} +text.trace.totalblocksplaced=Nombre total de blocs placés: [accent] {0} +text.trace.lastblockplaced=Dernier bloc placé: [accent] {0} +text.invalidid=ID client invalide! Soumettre un rapport de bug +text.server.bans=Interdictions +text.server.bans.none=Aucun joueur banni trouvé! +text.server.admins=Administrateurs +text.server.admins.none=Aucun administrateur trouvé! +text.server.add=Ajouter un serveur +text.server.delete=Êtes-vous sûr de vouloir supprimer ce serveur? +text.server.hostname=Héberger +text.server.edit=éditer le serveur +text.server.outdated=[crimson]Serveur obsolète![] +text.server.outdated.client=[Crimson]Client obsolète![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[jaune]Construction personnalisée +text.confirmban=Êtes-vous sûr de vouloir bannir ce joueur? +text.confirmunban=Êtes-vous sûr de vouloir annuler le ban de ce joueur? +text.confirmadmin=Êtes-vous sûr de vouloir faire de ce joueur un administrateur? +text.confirmunadmin=Êtes-vous sûr de vouloir supprimer le statut d'administrateur de ce joueur? +text.joingame.title=Rejoindre une partie +text.joingame.ip=IP : +text.disconnect=Déconnecté +text.connecting=[accent]Connexion ... +text.connecting.data=[accent] Chargement des données de la partie ... +text.connectfail=[crimson] Échec de la connexion au serveur : [orange] +text.server.port=Port : +text.server.addressinuse=Adresse déjà utilisée! +text.server.invalidport=Numéro de port incorrect. +text.server.error=[crimson]Erreur lors de l'hébergement du serveur: [orange] {0} +text.save.new=Nouvelle sauvegarde +text.save.overwrite=Êtes-vous sûr de vouloir remplacer cette sauvegarde? +text.overwrite=Écraser +text.save.none=Aucune sauvegarde trouvée! +text.saveload=[accent]Sauvegarde ... +text.savefail=Échec de la sauvegarde du jeu ! +text.save.delete.confirm=Êtes-vous sûr de vouloir supprimer cette sauvegarde? +text.save.delete=Supprimer +text.save.export=Exporter la sauvegarde +text.save.import.invalid=[orange]Cette sauvegarde est invalide! +text.save.import.fail=[crimson]Echec de l'importation de la sauvegarde: [orange] {0} +text.save.export.fail=[crimson]Échec de l'exportation de la sauvegarde: [orange] {0} +text.save.import=Importer la sauvegarde +text.save.newslot=Enregistrer le nom: +text.save.rename=Renommer +text.save.rename.text=Nouveau nom: +text.selectslot=Sélectionnez une sauvegarde. +text.slot=[accent]Emplacement {0} +text.save.corrupted=[orange]Le fichier enregistrer est corrompu ou invalide! +text.empty= +text.on=Allumer +text.off=Eteint +text.save.autosave=Sauvegarde automatique +text.save.map=Carte +text.save.wave=Vague : +text.save.difficulty=DIFFICULTÉ +text.save.date=Dernière sauvegarde: {0} +text.confirm=Confirmer +text.delete=Supprimer +text.ok=OK +text.open=Ouvrir +text.cancel=Annuler +text.openlink=Lien public +text.back=Retour +text.quit.confirm=Êtes-vous sûr de vouloir quitter? +text.changelog.title=Note de mise à jour +text.changelog.error=[Scarlet] Erreur lors de l'obtention du changement de serveur! Vérifiez votre connexion internet. +text.changelog.current=[jaune] [[Version actuelle] +text.changelog.latest=[orange][[Dernière version] +text.loading=[accent]Chargement ... +text.wave=[orange]Vague {0} +text.wave.waiting=Vague dans {0} +text.waiting=Attente... +text.enemies=ennemis +text.enemies.single=Ennemi +text.loadimage=Charger l'image +text.saveimage=Enregistrer l'image +text.editor.badsize=[orange]Dimensions de l'image non valides![] Dimensions de la carte valides: {0} +text.editor.errorimageload=Erreur lors du chargement du fichier image:[orange] {0} +text.editor.errorimagesave=Erreur lors de la sauvegarde du fichier image:[orange] {0} +text.editor.generate=Générer +text.editor.resize=Redimensionner +text.editor.loadmap=Charger la carte +text.editor.savemap=Enregistrer la carte +text.editor.loadimage=Charger l'image +text.editor.saveimage=Enregistrer l'image +text.editor.unsaved=[scarlet] Vous avez des changements non sauvegardés![] Êtes-vous sûr de vouloir quitter? +text.editor.resizemap=Redimensionner la carte +text.editor.mapname=Nom de la carte: +text.editor.overwrite=[accent]Attention! Cela écrasera la carte existante. +text.editor.selectmap=Sélectionnez une carte à charger: +text.width=Largeur: +text.height=Hauteur: +text.menu=Menu +text.play=Jouer +text.load=Charger +text.save=Sauvegarder +text.language.restart=Veuillez redémarrer votre jeu pour que les paramètres de langue soient appliqués. +text.settings.language=Langue +text.settings=Réglages +text.tutorial=Tutoriel +text.editor=Éditeur +text.mapeditor=Éditeur de carte +text.donate=Faire un don +text.settings.reset=Valeur par défaut. +text.settings.controls=Contrôles +text.settings.game=Jeu +text.settings.sound=Son +text.settings.graphics=Graphique +text.upgrades=Améliorations +text.purchased=[VERT]Créé! +text.weapons=Armes +text.paused=Pause +text.info.title=[accent]Info +text.error.title=[crimson]Une erreur est survenue +text.error.crashtitle=Une erreur est survenue +text.blocks.blockinfo=Bloquer les infos +text.blocks.powercapacity=capacité d'énergie +text.blocks.powershot=Energie/Tir +text.blocks.size=Taille +text.blocks.liquidcapacity=Capacité liquide +text.blocks.maxitemssecond=Max articles/seconde +text.blocks.powerrange=Gamme de puissance +text.blocks.itemcapacity=Capacité article +text.blocks.inputliquid=Entrée de liquide +text.blocks.inputitem=entré d'article +text.blocks.explosive=Hautement explosif ! +text.blocks.health=Santé +text.blocks.inaccuracy=Inexactitude +text.blocks.shots=tirs +text.blocks.inputcapacity=Capacité d'entrée +text.blocks.outputcapacity=Capacité de sortie +setting.difficulty.easy=facile +setting.difficulty.normal=normal +setting.difficulty.hard=difficile +setting.difficulty.insane=Extreme +setting.difficulty.purge=Purge +setting.difficulty.name=Difficulté: +setting.screenshake.name=Tremblement d'écran +setting.indicators.name=Indicateurs ennemis +setting.effects.name=Effets d'affichage +setting.sensitivity.name=Sensibilité de la manette +setting.saveinterval.name=Intervalle des sauvegardes auto +setting.seconds={0} secondes +setting.fullscreen.name=Plein écran +setting.multithread.name=Multithreading [scarlet] (instable!) +setting.fps.name=Afficher FPS +setting.vsync.name=VSync +setting.lasers.name=Afficher les rayons des lasers +setting.healthbars.name=Afficher les barres de santé des entités +setting.musicvol.name=volume musique +setting.mutemusic.name=Musique muette +setting.sfxvol.name=Volume SFX +setting.mutesound.name=Son muet +map.maze.name=Labyrinthe +map.fortress.name=forteresse +map.sinkhole.name=gouffre +map.caves.name=cavernes +map.volcano.name=volcan +map.caldera.name=chaudron +map.scorch.name=brûlure +map.desert.name=désert +map.island.name=Île +map.grassland.name=prairie +map.tundra.name=toundra +map.spiral.name=spirale +map.tutorial.name=tutoriel +text.keybind.title=Relier le clés +keybind.move_x.name=mouvement x +keybind.move_y.name=mouvement y +keybind.select.name=sélectionner +keybind.break.name=Pause +keybind.shoot.name=tirer +keybind.zoom_hold.name=tenir le zoom +keybind.zoom.name=zoom +keybind.block_info.name=bloc_info +keybind.menu.name=menu +keybind.pause.name=Pause +keybind.dash.name=attaque frontal +keybind.chat.name=chat +keybind.player_list.name=Liste des joueurs +keybind.console.name=console +keybind.rotate_alt.name=tourner_alt +keybind.rotate.name=Tourner +mode.waves.name=Vagues +mode.sandbox.name=bac à sable +mode.freebuild.name=construction libre +item.stone.name=pierre +item.coal.name=charbon +item.titanium.name=Titane +item.sand.name=sable +liquid.water.name=eau +liquid.lava.name=lave +liquid.oil.name=pétrole +block.door.name=porte +block.door-large.name=grande porte +block.conduit.name=conduit +block.pulseconduit.name=conduit à impulsion +block.liquidrouter.name=routeur de liquide +block.conveyor.name=transporteur +block.router.name=Routeur +block.junction.name=jonction +block.liquidjunction.name=jonction à liquide +block.sorter.name=trieur +block.smelter.name=fonderie +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.newgame=New Game +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.disconnect.data=Failed to load world data! +text.copylink=Copy Link +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.name=Thorium +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties index 569b89321b..b4c7f1e2a4 100644 --- a/core/assets/bundles/bundle_in_ID.properties +++ b/core/assets/bundles/bundle_in_ID.properties @@ -1,491 +1,495 @@ -text.about = Dibuat oleh [ROYAL]Anuken.[]\nAwalnya masuk di [orange]GDL[] MM Jam.\n\nKredit:\n- SFX dibuat dengan [YELLOW]bfxr[]\n- Musik dibuat oleh [GREEN]RoccoW[] / ditemukan di [lime]FreeMusicArchive.org[]\n\nTerima kasih khusus kepada:\n- [coral]MitchellFJN[]: playtesting dan umpan balik yang luas\n- [sky]Luxray5474[]: pekerjaan wiki, kontribusi kode\n- Semua penguji beta di itch.io dan Google Play\n -text.discord = Bergabunglah dengan Discord Mindustry! -text.gameover = Intinya hancur. -text.highscore = [YELLOW]Rekor baru! -text.lasted = Anda bertahan sampai gelombang -text.level.highscore = Skor Tinggi: [accent]{0} -text.level.delete.title = Konfirmasi Hapus -text.level.delete = Yakin ingin menghapus peta \"[orange]{0}\"? -text.level.select = Pilih Level -text.level.mode = Modus permainan: -text.savegame = Simpan Permainan -text.loadgame = Lanjutkan -text.joingame = Bermain Bersama -text.quit = Keluar -text.about.button = Tentang -text.name = Nama: -text.public = Publik -text.players = {0} pemain online -text.server.player.host = {0} (host) -text.players.single = {0} pemain online -text.server.mismatch = Kesalahan paket: kemungkinan versi client / server tidak sesuai.\nPastikan Anda dan host memiliki versi terbaru Mindustry! -text.server.closing = [accent]Menutup server... -text.server.kicked.kick = Anda telah dikeluarkan dari server! -text.server.kicked.invalidPassword = Kata sandi salah! -text.server.kicked.clientOutdated = Client versi lama! Update game Anda! -text.server.kicked.serverOutdated = Server versi lama! Tanyakan host untuk mengupdate! -text.server.connected = {0} telah bergabung. -text.server.disconnected = {0} telah terputus. -text.nohost = Tidak dapat meng-host server pada peta khusus! -text.hostserver = Host Server -text.host = Host -text.hosting = [accent]Membuka server... -text.hosts.refresh = Segarkan -text.hosts.discovering = Mencari game LAN -text.server.refreshing = Menyegarkan server -text.hosts.none = [lightgray]Tidak ada game LAN yang ditemukan! -text.host.invalid = [scarlet]Tidak dapat terhubung ke host. -text.server.friendlyfire = Tembak Sesama -text.server.add = Tambahkan Server -text.server.delete = Yakin ingin menghapus server ini? -text.server.hostname = Host: {0} -text.server.edit = Sunting Server -text.joingame.byip = Bergabung dengan IP... -text.joingame.title = Bermain Bersama -text.joingame.ip = IP: -text.disconnect = Sambungan terputus. -text.connecting = [accent]Menghubungkan... -text.connecting.data = [accent]Memuat data level... -text.connectfail = [crimson]Gagal terhubung ke server: [orange]{0} -text.server.port = Port: -text.server.addressinuse = Alamat sudah di pakai! -text.server.invalidport = Nomor port salah! -text.server.error = [crimson]Kesalahan server hosting: [orange]{0} -text.tutorial.back = < Sebelumnya -text.tutorial.next = Berikutnya > -text.save.new = Simpan Baru -text.save.overwrite = Yakin ingin mengganti slot simpan ini? -text.overwrite = Ganti -text.save.none = Tidak ada simpanan ditemukan! -text.saveload = [accent]Menyimpan... -text.savefail = Gagal menyimpan game! -text.save.delete.confirm = Yakin ingin menghapus save ini? -text.save.delete = Hapus -text.save.export = Ekspor Simpanan -text.save.import.invalid = [orange]Simpanan ini tidak valid! -text.save.import.fail = [crimson]Gagal mengimpor: [orange]{0} -text.save.export.fail = [crimson]Gagal mengekspor save: [orange]{0} -text.save.import = Impor Simpanan -text.save.newslot = Nama simpanan: -text.save.rename = Ganti nama -text.save.rename.text = Nama baru: -text.selectslot = Pilih simpanan. -text.slot = [accent]Slot{0} -text.save.corrupted = [orange]Simpanan rusak atau tidak valid! -text.empty = -text.on = Hidup -text.off = Mati -text.save.autosave = Simpan otomatis: {0} -text.save.map = Peta: {0} -text.save.wave = Gelombang {0} -text.save.date = Terakhir Disimpan: {0} -text.confirm = Konfirmasi -text.delete = Hapus -text.ok = OK -text.open = Buka -text.cancel = Batal -text.openlink = Buka tautan -text.back = Kembali -text.quit.confirm = Anda yakin ingin berhenti? -text.loading = [accent]Memuat... -text.wave = [orange]Gelombang {0} -text.wave.waiting = Gelombang dimulai {0} -text.waiting = Menunggu... -text.enemies = {0} musuh -text.enemies.single = {0} Musuh -text.loadimage = Buka Gambar -text.saveimage = Simpan Gambar -text.oregen = Generator Bijih -text.editor.badsize = [orange]Dimensi gambar tidak valid![]\nDimensi peta yang valid: {0} -text.editor.errorimageload = Kesalahan saat memuat file gambar:\n[orange]{0} -text.editor.errorimagesave = Kesalahan saat menyimpan file gambar:\n[orange]{0} -text.editor.generate = Hasilkan -text.editor.resize = Ubah ukuran -text.editor.loadmap = Buka Peta -text.editor.savemap = Simpan Peta -text.editor.loadimage = Buka Gambar -text.editor.saveimage = Simpan Gambar -text.editor.unsaved = [scarlet]Anda memiliki perubahan yang belum disimpan![]\nYakin ingin keluar? -text.editor.brushsize = Ukuran sikat: {0} -text.editor.noplayerspawn = Peta ini tidak memiliki spawnpoint pemain! -text.editor.manyplayerspawns = Peta tidak bisa memiliki lebih dari satu\nspawnpoint pemain! -text.editor.manyenemyspawns = Tidak dapat memiliki lebih dari\n{0} spawnpoint musuh! -text.editor.resizemap = Ubah ukuran peta -text.editor.resizebig = [scarlet]Peringatan!\n[]Peta yang lebih besar dari 256 unit mungkin nge-lag dan tidak stabil. -text.editor.mapname = Nama Peta: -text.editor.overwrite = [accent]Peringatan!\nIni akan mengganti peta yang ada. -text.editor.failoverwrite = [crimson]Tidak dapat mengganti peta default! -text.editor.selectmap = Pilih peta yang akan dimuat: -text.width = Lebar: -text.height = Tinggi: -text.randomize = Acak -text.apply = Terapkan -text.update = Perbarui -text.menu = Menu -text.play = Main -text.load = Buka -text.save = Simpan -text.language.restart = Silakan mulai ulang permainan Anda agar pengaturan bahasa mulai berlaku. -text.settings.language = Bahasa -text.settings = Pengaturan -text.tutorial = Tutorial -text.editor = Pengedit -text.mapeditor = Pengedit Peta -text.donate = Sumbangkan -text.settings.reset = Atur ulang ke Default -text.settings.controls = Kontrol -text.settings.game = Permainan -text.settings.sound = Suara -text.settings.graphics = Grafis -text.upgrades = Perbaruan -text.purchased = [LIME]Dibuat! -text.weapons = Senjata -text.paused = Jeda -text.respawn = Respawning dalam -text.info.title = [accent]Info -text.error.title = [crimson]Telah terjadi kesalahan -text.error.crashmessage = [SCARLET]Kesalahan tak terduga telah terjadi, yang menyebabkan kerusakan.\n[]Tolong laporkan keadaan yang tepat dimana kesalahan ini terjadi pada pengembang:\n[ORANGE] anukendev@gmail.com[] -text.error.crashtitle = Telah terjadi kesalahan -text.mode.break = Mode penghancur: {0} -text.mode.place = Mode penaruh: {0} -placemode.hold.name = garis -placemode.areadelete.name = area -placemode.touchdelete.name = sentuh -placemode.holddelete.name = tahan -placemode.none.name = tidak ada -placemode.touch.name = sentuh -placemode.cursor.name = kursor -text.blocks.extrainfo = [accent]info tambahan blok: -text.blocks.blockinfo = Info Blok -text.blocks.powercapacity = Kapasitas Tenaga -text.blocks.powershot = Tenaga/tembakan -text.blocks.powersecond = Tenaga/detik -text.blocks.powerdraindamage = Tenaga Dipakai/damage -text.blocks.shieldradius = Radius Perisai -text.blocks.itemspeedsecond = Kecepatan Barang/detik -text.blocks.range = Jangkauan -text.blocks.size = Ukuran -text.blocks.powerliquid = Tenaga/Cairan -text.blocks.maxliquidsecond = Batas cairan/detik -text.blocks.liquidcapacity = Kapasitas cairan -text.blocks.liquidsecond = Cairan/detik -text.blocks.damageshot = Damage/tembakan -text.blocks.ammocapacity = Kapasitas Amunisi -text.blocks.ammo = Amunisi -text.blocks.ammoitem = Amunisi/barang -text.blocks.maxitemssecond = Batas barang/detik -text.blocks.powerrange = Jangkauan tenaga -text.blocks.lasertilerange = Kotak jangkauan laser -text.blocks.capacity = Kapasitas -text.blocks.itemcapacity = Kapasitas Barang -text.blocks.maxpowergenerationsecond = Batas Penghasil Tenaga/detik -text.blocks.powergenerationsecond = Penghasil Tenaga/detik -text.blocks.generationsecondsitem = Waktu Penghasil (detik)/barang -text.blocks.input = Masukan -text.blocks.inputliquid = Cairan yang Masuk -text.blocks.inputitem = Barang yang Masuk -text.blocks.output = Keluar -text.blocks.secondsitem = Detik/barang -text.blocks.maxpowertransfersecond = Batas transfer tenaga/detik -text.blocks.explosive = Mudah meledak! -text.blocks.repairssecond = Perbaikan/detik -text.blocks.health = Darah -text.blocks.inaccuracy = Ketidaktelitian -text.blocks.shots = Tembakan -text.blocks.shotssecond = Tembakan/detik -text.blocks.fuel = Bahan Bakar -text.blocks.fuelduration = Durasi Bahan Bakar -text.blocks.maxoutputsecond = Batas keluar/detik -text.blocks.inputcapacity = Kapasitas masuk -text.blocks.outputcapacity = Kapasitas keluar -text.blocks.poweritem = Tenaga/barang -text.placemode = Mode Penempatan -text.breakmode = Mode Penghancur -text.health = darah -setting.difficulty.easy = mudah -setting.difficulty.normal = normal -setting.difficulty.hard = sulit -setting.difficulty.insane = sangat susah -setting.difficulty.purge = paling susah -setting.difficulty.name = Kesulitan: -setting.screenshake.name = Layar Bergoyang -setting.smoothcam.name = Kamera Halus -setting.indicators.name = Indikator Musuh -setting.effects.name = Efek Tampilan -setting.sensitivity.name = Sensitivitas Pengendali -setting.saveinterval.name = Waktu Simpan Otomatis -setting.seconds = {0} Detik -setting.fullscreen.name = Layar Penuh -setting.fps.name = Tunjukkan FPS -setting.vsync.name = VSync -setting.lasers.name = Tampilkan Laser Tenaga -setting.healthbars.name = Tampilkan Bar Darah Entitas -setting.pixelate.name = Layar Pixel -setting.musicvol.name = Volume Musik -setting.mutemusic.name = Bisukan Musik -setting.sfxvol.name = Volume Suara -setting.mutesound.name = Bisukan Suara -map.maze.name = labirin -map.fortress.name = benteng -map.sinkhole.name = lubang pembuangan -map.caves.name = gua -map.volcano.name = gunung berapi -map.caldera.name = kaldera -map.scorch.name = penghangusan -map.desert.name = gurun -map.island.name = pulau -map.grassland.name = padang rumput -map.tundra.name = tundra -map.spiral.name = spiral -map.tutorial.name = tutorial -tutorial.intro.text = [yellow]Selamat datang di tutorial.[] Untuk memulai, tekan 'berikutnya'. -tutorial.moveDesktop.text = Untuk bergerak, gunakan tombol [orange][[WASD][]. Tahan tombol [orange]shift[] untuk mempercepat. Tahan [orange]CTRL[] saat menggunakan [orange]scrollwheel[] untuk memperbesar atau memperkecil tampilan. -tutorial.shoot.text = Gunakan mouse anda untuk mengarahkan, tahan [orange]tombol kiri mouse[] untuk menembak. Cobalah menembaki [yellow]target[]. -tutorial.moveAndroid.text = Untuk menggeser tampilan, seret satu jari ke layar. Jepit dan seret untuk memperbesar atau memperkecil tampilan. -tutorial.placeSelect.text = Coba pilih [yellow]konveyor[] dari menu blok di kanan bawah. -tutorial.placeConveyorDesktop.text = Gunakan [orange][[scrollwheel][] untuk memutar konveyor menghadap [orange]ke depan[], lalu letakkan di [yellow]lokasi yang ditandai[] menggunakan [orange][[tombol kiri mouse]][]. -tutorial.placeConveyorAndroid.text = Gunakan [orange][[tombol putar]][] untuk memutar konveyor menghadap [orange]ke depan[], seret ke posisi dengan satu jari, lalu letakkan di [yellow]lokasi yang ditandai[] dengan menggunakan [orange][[tanda centang][]. -tutorial.placeConveyorAndroidInfo.text = Sebagai alternatif, Anda dapat menekan ikon crosshair di kiri bawah untuk beralih ke [orange][[mode sentuh]][], dan letakkan blok dengan mengetuk layar. Dalam mode sentuh, blok bisa diputar dengan panah di kiri bawah. Tekan [yellow]berikutnya[] untuk mencobanya. -tutorial.placeDrill.text = Sekarang, pilih dan tempatkan [yellow]pertambangan battu[] di lokasi yang ditandai. -tutorial.blockInfo.text = Jika Anda ingin mempelajari lebih lanjut tentang blok, Anda dapat menekan [orange]tanda tanya[] di bagian kanan atas untuk membaca deskripsinya. -tutorial.deselectDesktop.text = Anda bisa membatalkan pemilihan blok menggunakan [orange][[tombol mouse kanan][]. -tutorial.deselectAndroid.text = Anda dapat membatalkan pemilihan blok dengan menekan tombol [orange]X (silang)[]. -tutorial.drillPlaced.text = Pertambangannya sekarang akan menghasilkan [yellow]batu[] yang dikeluarkan ke konveyor, lalu memindahkannya ke [yellow]intinya[]. -tutorial.drillInfo.text = Bijih yang berbeda membutuhkan pertambangan yang berbeda. Batu membutuhkan pertambangan batu, besi membutuhkan pertambangan besi, dll. -tutorial.drillPlaced2.text = Memindahkan barang ke dalam inti menempatkannya di [yellow]inventaris barang[] Anda, di kiri atas. Menempatkan blok menggunakan barang dari inventaris Anda. -tutorial.moreDrills.text = Anda bisa menghubungkan banyak pertambangan dan konveyor bersama-sama, seperti biasa. -tutorial.deleteBlock.text = Anda dapat menghapus blok dengan mengeklik [orange]tombol mouse kanan[] di blok yang ingin Anda hapus. Coba hapus konveyor ini. -tutorial.deleteBlockAndroid.text = Anda dapat menghapus blok dengan [orange]memilih crosshair[] di [orange]menu mode penghancur[] di kiri bawah dan mengetuk bloknya. Coba hapus konveyor ini. -tutorial.placeTurret.text = Sekarang, pilih dan tempatkan [yellow]turret[] di [yellow]lokasi yang ditandai[]. -tutorial.placedTurretAmmo.text = Turret ini sekarang akan menerima [yellow]amunisi[] dari konveyor. Anda dapat melihat berapa banyak amunisi yang dimiliki dengan menggeser kursor di bloknya dan memeriksa di [green]bilah hijau[]. -tutorial.turretExplanation.text = Turret secara otomatis akan menembak musuh terdekat dalam jangkauan, selama mereka memiliki cukup amunisi. -tutorial.waves.text = Setiap [yellow]60[] detik, gelombang [coral]musuh[] akan muncul di lokasi tertentu dan berusaha menghancurkan intinya. -tutorial.coreDestruction.text = Tujuan Anda adalah untuk [yellow]mempertahankan intinya[]. Jika intinya hancur, Anda [coral]kalah dalam permainan[]. -tutorial.pausingDesktop.text = Jika Anda perlu istirahat sebentar, tekan [orange]tombol jeda[] di bagian kiri atas atau [orange]tombol spasi[] untuk menghentikan sementara permainan. Anda masih bisa memilih dan menempatkan blok sambil berhenti, tapi tidak bisa bergerak atau menembak. -tutorial.pausingAndroid.text = Jika Anda perlu istirahat sebentar, tekan [orange]tombol jeda[] di kiri atas untuk menjeda permainan. Anda masih bisa menghapus dan menempatkan blok sambil berhenti sebentar. -tutorial.purchaseWeapons.text = Anda bisa membeli [yellow]senjata baru[] untuk robot Anda dengan membuka menu upgrade di kiri bawah. -tutorial.switchWeapons.text = Untuk mengganti senjata, klik ikonnya di kiri bawah, atau gunakan angka [orange][[1-9][]. -tutorial.spawnWave.text = Gelombang sekarang datang. Hancurkan mereka. -tutorial.pumpDesc.text = Pada gelombang selanjutnya, Anda mungkin perlu menggunakan [yellow]pompa[] untuk mendistribusikan cairan untuk generator atau ekstraktor. -tutorial.pumpPlace.text = Pompa bekerja seperti dengan pertambangan, namun mereka menghasilkan cairan dan bukan barang. Cobalah menempatkan pompa pada [yellow]minyak yang ditunjuk[]. -tutorial.conduitUse.text = Sekarang tempatkan [orange]saluran[] yang mengarah jauh dari pompa. -tutorial.conduitUse2.text = Dan beberapa lagi... -tutorial.conduitUse3.text = Dan beberapa lagi... -tutorial.generator.text = Sekarang, tempatkan [orange]blok generator pembakaran[] di ujung saluran. -tutorial.generatorExplain.text = Generator ini sekarang akan menciptakan [yellow]tenaga[] dari minyak. -tutorial.lasers.text = Tenaga didistribusikan menggunakan [yellow]laser tenaga[]. Putar dan tempatkan di sini. -tutorial.laserExplain.text = Generator sekarang akan memindahkan tenaga ke blok laser. Sinar [yellow]terang[] menandakan bahwa saat ini mentransmisikan tenaga, dan sinar [yellow]transparan[] berarti tidak. -tutorial.laserMore.text = Anda dapat memeriksa berapa banyak tenaga yang dimiliki blok dengan memindahkan kursor/mengetuk di atasnya dan memeriksa [yellow]bar kuning[] di bagian atas. -tutorial.healingTurret.text = Laser ini bisa digunakan untuk menyalakan [lime]turret perbaikan[]. Tempatkan satu di sini. -tutorial.healingTurretExplain.text = Selama memiliki tenaga, turret ini akan [lime]memperbaiki blok terdekat[]. Saat bermain, pastikan Anda memasukkannya ke markas Anda secepat mungkin! -tutorial.smeltery.text = Banyak blok yang membutuhkan [orange]baja[] agar dapat dibangun, yang membutuhkan [orange]peleburan[] untuk dibuat. Tempatkan satu di sini. -tutorial.smelterySetup.text = Peleburan ini sekarang akan menghasilkan [orange]baja[] dari besi yang masuk, dengan batubara sebagai bahan bakarnya. -tutorial.tunnelExplain.text = Perhatikan juga bahwa barang-barang itu masuk melalui [orange]blok terowongan[] dan muncul di sisi lain, melewati blok batu. Perlu diingat bahwa terowongan hanya bisa melalui sampai 2 blok. -tutorial.end.text = Dan itu menyimpulkan tutorialnya! Semoga berhasil! -keybind.move_x.name = gerak_x -keybind.move_y.name = gerak_y -keybind.select.name = pilih -keybind.break.name = hapus -keybind.shoot.name = tembak -keybind.zoom_hold.name = perbesar_tahan -keybind.zoom.name = perbesar -keybind.menu.name = menu -keybind.pause.name = jeda -keybind.dash.name = berlari -keybind.rotate_alt.name = putar_alt -keybind.rotate.name = putar -keybind.weapon_1.name = senjata_1 -keybind.weapon_2.name = senjata_2 -keybind.weapon_3.name = senjata_3 -keybind.weapon_4.name = senjata_4 -keybind.weapon_5.name = senjata_5 -keybind.weapon_6.name = senjata_6 -mode.waves.name = gelombang -mode.sandbox.name = sandbox -mode.freebuild.name = freebuild -upgrade.standard.name = standar -upgrade.standard.description = Robot standar. -upgrade.blaster.name = blaster -upgrade.blaster.description = Menembakan sebuah peluru yang lemah dan lambat. -upgrade.triblaster.name = triblaster -upgrade.triblaster.description = Menembakan 3 peluru secara menyebar. -upgrade.clustergun.name = clustergun -upgrade.clustergun.description = Menembakan sebuah granat eksplosif yang tidak akurat. -upgrade.beam.name = meriam sinar -upgrade.beam.description = Menembakan sinar laser jarak jauh. -upgrade.vulcan.name = vulcan -upgrade.vulcan.description = Menembakkan rombongan peluru dengan cepat. -upgrade.shockgun.name = shockgun -upgrade.shockgun.description = Menembakkan ledakan yang menghancurkan dari pecahan peluru yang terisi. -item.stone.name = batu -item.iron.name = besi -item.coal.name = batu bara -item.steel.name = baja -item.titanium.name = titanium -item.dirium.name = dirium -item.thorium.name = thorium -item.sand.name = pasir -liquid.water.name = air -liquid.plasma.name = plasma -liquid.lava.name = lahar -liquid.oil.name = minyak -block.weaponfactory.name = pabrik senjata -block.weaponfactory.fulldescription = Dipakai untuk membuat senjata bagi robot pemain. Klik untuk memakai. Otomatis mengambil sumber daya dari inti. -block.air.name = udara -block.blockpart.name = bagian blok -block.deepwater.name = air dangkal -block.water.name = air -block.lava.name = lahar -block.oil.name = minyak -block.stone.name = batu -block.blackstone.name = batu hitam -block.iron.name = besi -block.coal.name = batu bara -block.titanium.name = titanium -block.thorium.name = thorium -block.dirt.name = tanah -block.sand.name = pasir -block.ice.name = es -block.snow.name = salju -block.grass.name = rumput -block.sandblock.name = blok pasir -block.snowblock.name = blok salju -block.stoneblock.name = blok batu -block.blackstoneblock.name = blok batu hitam -block.grassblock.name = blok rumput -block.mossblock.name = blok lumut -block.shrub.name = belukar -block.rock.name = batu -block.icerock.name = batu es -block.blackrock.name = batu hitam -block.dirtblock.name = blok tanah -block.stonewall.name = dinding batu -block.stonewall.fulldescription = Sebuah blok defensif yang murah. Berguna untuk melindungi inti dan turret di beberapa gelombang pertama. -block.ironwall.name = dinding besi -block.ironwall.fulldescription = Blok defensif dasar. Menyediakan perlindungan dari musuh. -block.steelwall.name = dinding baja -block.steelwall.fulldescription = Sebuah blok defensif standar. Perlindungan yang memadai dari musuh. -block.titaniumwall.name = dinding titanium -block.titaniumwall.fulldescription = Blok pertahanan yang kuat. Menyediakan perlindungan dari musuh. -block.duriumwall.name = dinding dirium -block.duriumwall.fulldescription = Blok pertahanan yang sangat kuat. Menyediakan perlindungan dari musuh. -block.compositewall.name = dinding komposit -block.steelwall-large.name = dinding baja besar -block.steelwall-large.fulldescription = Sebuah blok defensif standar. Membentang beberapa ubin. -block.titaniumwall-large.name = dinding titanium besar -block.titaniumwall-large.fulldescription = Blok pertahanan yang kuat. Membentang beberapa ubin. -block.duriumwall-large.name = dinding dirium yang besar -block.duriumwall-large.fulldescription = Blok pertahanan yang sangat kuat. Membentang beberapa ubin. -block.titaniumshieldwall.name = dinding perisai -block.titaniumshieldwall.fulldescription = Sebuah blok defensif yang kuat, dengan tambahan perisai. Membutuhkan tenaga. Menggunakan energi untuk menyerap peluru musuh. Dianjurkan untuk menggunakan pemercepat tenaga untuk memberi energi pada blok ini. -block.repairturret.name = turret perbaikan -block.repairturret.fulldescription = Memperbaiki blok terdekat yang rusak dengan lambat. Menggunakan sedikit tenaga. -block.megarepairturret.name = perbaikan turret II -block.megarepairturret.fulldescription = Memperbaiki blok yang rusak dengan normal. Menggunakan tenaga. -block.shieldgenerator.name = pembangkit perisai -block.shieldgenerator.fulldescription = Blok defensif yang maju. Mellindungi semua blok dalam radius dari serangan. Menggunakan tenaga dengan lambat saat menganggur, namun menyalurkan energi dengan cepat pada kontak peluru. -block.door.name = pintu -block.door.fulldescription = Blok yang bisa dibuka dan ditutup dengan mengetuknya. -block.door-large.name = pintu besar -block.door-large.fulldescription = Blok yang bisa dibuka dan ditutup dengan mengetuknya. -block.conduit.name = saluran -block.conduit.fulldescription = Blok pengangkut cairan dasar. Bekerja seperti konveyor, tapi dengan cairan. Terbaik digunakan dengan pompa atau saluran lainnya. Bisa digunakan sebagai jembatan di atas cairan untuk musuh dan pemain. -block.pulseconduit.name = saluran cepat -block.pulseconduit.fulldescription = Blok pengangkut cairan tingkat lanjut. Mengangkut cairan lebih cepat dan menyimpan lebih banyak dari pada saluran standar. -block.liquidrouter.name = router cairan -block.liquidrouter.fulldescription = Bekerja seperti router. Menerima masukan cairan dari satu sisi dan mengeluarkannya ke sisi yang lain. Berguna untuk pemisahan cairan dari satu saluran ke beberapa saluran lainnya. -block.conveyor.name = konveyor -block.conveyor.fulldescription = Blok dasar pengangkut barang. Memindahkan barang ke depan dan secara otomatis menyimpannya ke turret, ekstraktor, dan pertambangan. Bisa diputar. Bisa digunakan sebagai jembatan di atas cairan untuk musuh dan pemain. -block.steelconveyor.name = konveyor baja -block.steelconveyor.fulldescription = Blok transportasi barang lanjutan. Memindahkan barang lebih cepat dari konveyor standar. -block.poweredconveyor.name = konveyor cepat -block.poweredconveyor.fulldescription = Blok terbaik untuk pengangkutan barang. Memindahkan barang lebih cepat dari konveyor baja. -block.router.name = router -block.router.fulldescription = Menerima item dari satu arah dan mengeluarkannya ke 3 arah. Bisa juga menyimpan sejumlah barang. Berguna untuk membelah bahan dari satu pertambangan ke beberapa turret. -block.junction.name = persimpangan jalan -block.junction.fulldescription = Bertindak sebagai jembatan untuk dua sabuk persimpangan. Berguna dalam situasi dengan dua konveyor berbeda yang membawa bahan berbeda ke lokasi yang berbeda. -block.conveyortunnel.name = terowongan konveyor -block.conveyortunnel.fulldescription = Memindahkan barang di bawah blok. Untuk menggunakan, tempatkan satu terowongan yang menuju ke terowongan di bawah blok, dan satu di sisi lain. Pastikan kedua terowongan menghadap ke arah yang berlawanan, yaitu menuju blok yang mereka masukkan atau keluarkan. -block.liquidjunction.name = persimpangan cairan -block.liquidjunction.fulldescription = Bertindak sebagai jembatan untuk dua saluran persimpangan. Berguna dalam situasi dengan dua saluran berbeda yang membawa cairan berbeda ke lokasi yang berbeda. -block.liquiditemjunction.name = persimpangan barang-cairan -block.liquiditemjunction.fulldescription = Bertindak sebagai jembatan untuk menyilang saluran dan konveyor. -block.powerbooster.name = pemercepat tenaga -block.powerbooster.fulldescription = Mendistribusikan tenaga ke semua blok dalam radiusnya. -block.powerlaser.name = laser tenaga -block.powerlaser.fulldescription = Membuat laser yang mentransmisikan daya ke blok di depannya. Tidak menghasilkan tenaga itu sendiri. Terbaik digunakan dengan generator atau laser lainnya. -block.powerlaserrouter.name = router laser -block.powerlaserrouter.fulldescription = Laser yang mendistribusikan tenaga ke tiga arah sekaligus. Berguna dalam situasi di mana diperlukan tenaga ke beberapa blok dari satu generator. -block.powerlasercorner.name = sudut laser -block.powerlasercorner.fulldescription = Laser yang mendistribusikan tenaga ke dua arah sekaligus. Berguna dalam situasi di mana diperlukan tenaga ke beberapa blok dari satu generator, dan arah router kurang tepat. -block.teleporter.name = teleporter -block.teleporter.fulldescription = Blok transportasi barang lanjutan. Teleporter memasukkan barang ke teleporter lain dengan warna yang sama. Tidak ada apa-apa jika tidak ada teleporter dengan warna yang sama. Jika beberapa teleporter memiliki warna yang sama, teleporter dipilih secara acak. Menggunakan tenaga. Ketuk/klik untuk mengubah warna. -block.sorter.name = penyortir -block.sorter.fulldescription = Menyortir barang menurut jenis bahannya. Bahan yang diterima ditandai dengan warna di blok. Semua item yang sesuai dengan jenis bahan dilepaskan ke depan, segala sesuatu yang lain dikeluarkan ke kiri dan kanan. -block.core.name = inti -block.pump.name = pompa -block.pump.fulldescription = Memompa cairan dari sumber blok- biasanya air, lahar atau minyak. Mengeluarkan cairan ke saluran terdekat. -block.fluxpump.name = pompa flux -block.fluxpump.fulldescription = Sebuah versi lanjutan dari pompa. Menyimpan lebih banyak cairan dan memompa cairan lebih cepat. -block.smelter.name = peleburan -block.smelter.fulldescription = Blok kerajinan esensial. Saat dimasukkan 1 besi dan 1 batu bara sebagai bahan bakar, akan mengeluarkan satu baja. Disarankan untuk memasukkan besi dan batu bara ke sabuk yang berbeda untuk mencegah penyumbatan. -block.crucible.name = peleburan dirium -block.crucible.fulldescription = Sebuah blok kerajinan yang maju. Saat dimasukkan 1 titanium, 1 baja dan 1 batu bara sebagai bahan bakar, mengeluarkan satu dirium. Disarankan untuk memasukkan batubara, baja dan titanium pada sabuk yang berbeda untuk mencegah penyumbatan. -block.coalpurifier.name = ekstraktor batubara -block.coalpurifier.fulldescription = Blok ekstraktor dasar. mengeluarkan batu bara saat dipasok dengan air dan batu dalam skala yang besar. -block.titaniumpurifier.name = ekstraktor titanium -block.titaniumpurifier.fulldescription = Blok ekstraktor standar. mengeluarkan titanium bila dipasok dengan air dan besi dalam skala yang besar. -block.oilrefinery.name = penyulingan minyak -block.oilrefinery.fulldescription = Menyuling sejumlah minyak menjadi batubara. Berguna untuk memasok turret berbasis batubara saat penambangan batubara langka. -block.stoneformer.name = pembentuk batu -block.stoneformer.fulldescription = Mengubah lahar ke dalam batu. Berguna untuk menghasilkan batu dalam jumlah besar untuk pemurni batu bara. -block.lavasmelter.name = peleburan lava -block.lavasmelter.fulldescription = Menggunakan lahar untuk mengubah besi menjadi baja. Sebuah alternatif untuk peleburan batubara. Berguna dalam situasi di mana pertambangan batubara langka. -block.stonedrill.name = pertambangan batu -block.stonedrill.fulldescription = Pertambangan penting. Saat diletakkan di atas ubin batu, akan menghasilkan batu pada kecepatan yang lambat tanpa batas waktu. -block.irondrill.name = pertambangan besi -block.irondrill.fulldescription = Pertambangan dasar. Saat diletakkan di atas ubin bijih besi, akan mengeluarkan besi pada kecepatan yang lambat tanpa batas waktu. -block.coaldrill.name = pertambangan batubara -block.coaldrill.fulldescription = Pertambangan dasar. Saat ditempatkan di ubin bijih batubara, akan mengeluarkan batu bara pada kecepatan yang lambat tanpa batas waktu. -block.thoriumdrill.name = pertambangan thorium -block.thoriumdrill.fulldescription = Sebuah pertambangan yang canggih. Saat ditempatkan di ubin bijih thorium, akan mengeluarkan thorium pada kecepatan lambat tanpa batas waktu. -block.titaniumdrill.name = pertambangan titanium -block.titaniumdrill.fulldescription = Sebuah pertambangan yang canggih. Saat ditempatkan pada ubin bijih titanium, akan mengeluarkan titanium pada kecepatan lambat tanpa batas waktu. -block.omnidrill.name = pertambangan super -block.omnidrill.fulldescription = Pertambangan yang terbaik. Akan saya tambang bijih apapun itu ditempatkan pada kecepatan tinggi. -block.coalgenerator.name = pembangkit tenaga batubara -block.coalgenerator.fulldescription = Generator penting. Menghasilkan tenaga dari batu bara. Keluarkan tenaga sebagai laser ke 4 sisinya. -block.thermalgenerator.name = pembangkit tenaga panas -block.thermalgenerator.fulldescription = Menghasilkan tenaga dari lahar. Mengeluarkan tenaga sebagai laser ke 4 sisi. -block.combustiongenerator.name = pembangkit tenaga minyak -block.combustiongenerator.fulldescription = Menghasilkan tenaga dari minyak. Mengeluarkan tenaga sebagai laser ke 4 sisi. -block.rtgenerator.name = pembangkit tenaga radioaktif -block.rtgenerator.fulldescription = Menghasilkan sedikit tenaga dari peluruhan radioaktif thorium. Mengeluarkan tenaga sebagai laser ke 4 sisi. -block.nuclearreactor.name = reaktor nuklir -block.nuclearreactor.fulldescription = Versi lanjutan Pembangkit Tenaga Radioaktif, dan generator tenaga tertinggi. Menghasilkan tenaga dari thorium. Membutuhkan pendinginan air konstan. Sangat mudah menguap; akan meledak dengan hebat jika tidak cukup jumlah pendingin yang diberikan. -block.turret.name = turret -block.turret.fulldescription = Sebuah menara dasar yang murah. Menggunakan batu untuk amunisi. Memiliki jangkauan yang sedikit lebih banyak daripada turret ganda. -block.doubleturret.name = turret ganda -block.doubleturret.fulldescription = Versi turret standar yang sedikit lebih bertenaga. Menggunakan batu untuk amunisi. Memberikan damage secara signifikan lebih banyak, namun memiliki jangkauan yang lebih rendah. Menembak dua peluru. -block.machineturret.name = turret cepat -block.machineturret.fulldescription = Sebuah menara standar. Menggunakan besi untuk amunisi. Memiliki tembakan yang cepat dengan damage yang layak. -block.shotgunturret.name = turret split -block.shotgunturret.fulldescription = Sebuah turret standar. Menggunakan besi untuk amunisi. Menembakkan 7 peluru. Jaraknya pendek, namun damage-nya lebih tinggi daripada turret cepat. -block.flameturret.name = turret api -block.flameturret.fulldescription = Turret jarak dekat lanjutan. Menggunakan batubara untuk amunisi. Memiliki jangkauan yang pendek, namun sangat tinggi damage-nya. Bagus untuk jarak dekat. Dianjurkan untuk digunakan dibalik dinding. -block.sniperturret.name = turret railgun -block.sniperturret.fulldescription = Turret jarak jauh lanjutan. Menggunakan baja untuk amunisi. Kerusakan yang sangat tinggi, namun menembak dengan lambat. Mahal untuk digunakan, tapi bisa ditempatkan jauh dari garis musuh karena jangkauannya. -block.mortarturret.name = turret flak -block.mortarturret.fulldescription = Turret dengan akurasi pendek dan damage eksplosif. Menggunakan batubara untuk amunisi. Menembakkan peluru yang meledak lalu menjadi pecahan peluru. Berguna untuk kerumunan musuh yang besar. -block.laserturret.name = turret laser -block.laserturret.fulldescription = Turret satu target. Menggunakan tenaga. Memiliki jarak sedang yang bagus. Target tunggal saja. Tidak pernah meleset. -block.waveturret.name = turret tesla -block.waveturret.fulldescription = Turret target banyak. Menggunakan tenaga. Jaraknya sedang. Tidak pernah meleset. Rata-rata damage-nya kecil, namun bisa menembak beberapa musuh bersamaan dengan petir berantai. -block.plasmaturret.name = turret plasma -block.plasmaturret.fulldescription = Versi yang sangat maju dari turret api. Menggunakan batubara sebagai amunisi. Damage yang sangat tinggi, jaraknya pendek sampai sedang. -block.chainturret.name = turret berantai -block.chainturret.fulldescription = Menara api yang menembak dengan cepat. Menggunakan thorium sebagai amunisi. Menembak peluru besar dengan kecepatan tinggi. Jaraknya sedang. Membentang beberapa ubin. Sangat tangguh. -block.titancannon.name = meriam titan -block.titancannon.fulldescription = Turret jarak jauh terakhir. Menggunakan thorium sebagai amunisi. Menembakkan peluru yang meledak dengan cipratan besar dengan kecepatan sedang. Jarak jauh. Membentang beberapa ubin. Sangat tangguh. -block.playerspawn.name = spawn pemain -block.enemyspawn.name = spawn musuh \ No newline at end of file +text.about=Dibuat oleh [ROYAL]Anuken.[]\nAwalnya masuk di [orange]GDL[] MM Jam.\n\nKredit:\n- SFX dibuat dengan [YELLOW]bfxr[]\n- Musik dibuat oleh [GREEN]RoccoW[] / ditemukan di [lime]FreeMusicArchive.org[]\n\nTerima kasih khusus kepada:\n- [coral]MitchellFJN[]: playtesting dan umpan balik yang luas\n- [sky]Luxray5474[]: pekerjaan wiki, kontribusi kode\n- Semua penguji beta di itch.io dan Google Play\n +text.discord=Bergabunglah dengan Discord Mindustry! +text.gameover=Intinya hancur. +text.highscore=[YELLOW]Rekor baru! +text.lasted=Anda bertahan sampai gelombang +text.level.highscore=Skor Tinggi: [accent]{0} +text.level.delete.title=Konfirmasi Hapus +text.level.select=Pilih Level +text.level.mode=Modus permainan: +text.savegame=Simpan Permainan +text.loadgame=Lanjutkan +text.joingame=Bermain Bersama +text.quit=Keluar +text.about.button=Tentang +text.name=Nama: +text.players={0} pemain online +text.players.single={0} pemain online +text.server.mismatch=Kesalahan paket: kemungkinan versi client / server tidak sesuai.\nPastikan Anda dan host memiliki versi terbaru Mindustry! +text.server.closing=[accent]Menutup server... +text.server.kicked.kick=Anda telah dikeluarkan dari server! +text.server.kicked.invalidPassword=Kata sandi salah! +text.server.kicked.clientOutdated=Client versi lama! Update game Anda! +text.server.kicked.serverOutdated=Server versi lama! Tanyakan host untuk mengupdate! +text.server.connected={0} telah bergabung. +text.server.disconnected={0} telah terputus. +text.nohost=Tidak dapat meng-host server pada peta khusus! +text.hostserver=Host Server +text.host=Host +text.hosting=[accent]Membuka server... +text.hosts.refresh=Segarkan +text.hosts.discovering=Mencari game LAN +text.server.refreshing=Menyegarkan server +text.hosts.none=[lightgray]Tidak ada game LAN yang ditemukan! +text.host.invalid=[scarlet]Tidak dapat terhubung ke host. +text.server.friendlyfire=Tembak Sesama +text.server.add=Tambahkan Server +text.server.delete=Yakin ingin menghapus server ini? +text.server.hostname=Host: {0} +text.server.edit=Sunting Server +text.joingame.title=Bermain Bersama +text.joingame.ip=IP: +text.disconnect=Sambungan terputus. +text.connecting=[accent]Menghubungkan... +text.connecting.data=[accent]Memuat data level... +text.connectfail=[crimson]Gagal terhubung ke server: [orange]{0} +text.server.port=Port: +text.server.addressinuse=Alamat sudah di pakai! +text.server.invalidport=Nomor port salah! +text.server.error=[crimson]Kesalahan server hosting: [orange]{0} +text.save.new=Simpan Baru +text.save.overwrite=Yakin ingin mengganti slot simpan ini? +text.overwrite=Ganti +text.save.none=Tidak ada simpanan ditemukan! +text.saveload=[accent]Menyimpan... +text.savefail=Gagal menyimpan game! +text.save.delete.confirm=Yakin ingin menghapus save ini? +text.save.delete=Hapus +text.save.export=Ekspor Simpanan +text.save.import.invalid=[orange]Simpanan ini tidak valid! +text.save.import.fail=[crimson]Gagal mengimpor: [orange]{0} +text.save.export.fail=[crimson]Gagal mengekspor save: [orange]{0} +text.save.import=Impor Simpanan +text.save.newslot=Nama simpanan: +text.save.rename=Ganti nama +text.save.rename.text=Nama baru: +text.selectslot=Pilih simpanan. +text.slot=[accent]Slot{0} +text.save.corrupted=[orange]Simpanan rusak atau tidak valid! +text.empty= +text.on=Hidup +text.off=Mati +text.save.autosave=Simpan otomatis: {0} +text.save.map=Peta: {0} +text.save.wave=Gelombang {0} +text.save.date=Terakhir Disimpan: {0} +text.confirm=Konfirmasi +text.delete=Hapus +text.ok=OK +text.open=Buka +text.cancel=Batal +text.openlink=Buka tautan +text.back=Kembali +text.quit.confirm=Anda yakin ingin berhenti? +text.loading=[accent]Memuat... +text.wave=[orange]Gelombang {0} +text.wave.waiting=Gelombang dimulai {0} +text.waiting=Menunggu... +text.enemies={0} musuh +text.enemies.single={0} Musuh +text.loadimage=Buka Gambar +text.saveimage=Simpan Gambar +text.editor.badsize=[orange]Dimensi gambar tidak valid![]\nDimensi peta yang valid: {0} +text.editor.errorimageload=Kesalahan saat memuat file gambar:\n[orange]{0} +text.editor.errorimagesave=Kesalahan saat menyimpan file gambar:\n[orange]{0} +text.editor.generate=Hasilkan +text.editor.resize=Ubah ukuran +text.editor.loadmap=Buka Peta +text.editor.savemap=Simpan Peta +text.editor.loadimage=Buka Gambar +text.editor.saveimage=Simpan Gambar +text.editor.unsaved=[scarlet]Anda memiliki perubahan yang belum disimpan![]\nYakin ingin keluar? +text.editor.resizemap=Ubah ukuran peta +text.editor.mapname=Nama Peta: +text.editor.overwrite=[accent]Peringatan!\nIni akan mengganti peta yang ada. +text.editor.selectmap=Pilih peta yang akan dimuat: +text.width=Lebar: +text.height=Tinggi: +text.menu=Menu +text.play=Main +text.load=Buka +text.save=Simpan +text.language.restart=Silakan mulai ulang permainan Anda agar pengaturan bahasa mulai berlaku. +text.settings.language=Bahasa +text.settings=Pengaturan +text.tutorial=Tutorial +text.editor=Pengedit +text.mapeditor=Pengedit Peta +text.donate=Sumbangkan +text.settings.reset=Atur ulang ke Default +text.settings.controls=Kontrol +text.settings.game=Permainan +text.settings.sound=Suara +text.settings.graphics=Grafis +text.upgrades=Perbaruan +text.purchased=[LIME]Dibuat! +text.weapons=Senjata +text.paused=Jeda +text.info.title=[accent]Info +text.error.title=[crimson]Telah terjadi kesalahan +text.error.crashtitle=Telah terjadi kesalahan +text.blocks.blockinfo=Info Blok +text.blocks.powercapacity=Kapasitas Tenaga +text.blocks.powershot=Tenaga/tembakan +text.blocks.size=Ukuran +text.blocks.liquidcapacity=Kapasitas cairan +text.blocks.maxitemssecond=Batas barang/detik +text.blocks.powerrange=Jangkauan tenaga +text.blocks.itemcapacity=Kapasitas Barang +text.blocks.inputliquid=Cairan yang Masuk +text.blocks.inputitem=Barang yang Masuk +text.blocks.explosive=Mudah meledak! +text.blocks.health=Darah +text.blocks.inaccuracy=Ketidaktelitian +text.blocks.shots=Tembakan +text.blocks.inputcapacity=Kapasitas masuk +text.blocks.outputcapacity=Kapasitas keluar +setting.difficulty.easy=mudah +setting.difficulty.normal=normal +setting.difficulty.hard=sulit +setting.difficulty.insane=sangat susah +setting.difficulty.purge=paling susah +setting.difficulty.name=Kesulitan: +setting.screenshake.name=Layar Bergoyang +setting.indicators.name=Indikator Musuh +setting.effects.name=Efek Tampilan +setting.sensitivity.name=Sensitivitas Pengendali +setting.saveinterval.name=Waktu Simpan Otomatis +setting.seconds={0} Detik +setting.fullscreen.name=Layar Penuh +setting.fps.name=Tunjukkan FPS +setting.vsync.name=VSync +setting.lasers.name=Tampilkan Laser Tenaga +setting.healthbars.name=Tampilkan Bar Darah Entitas +setting.musicvol.name=Volume Musik +setting.mutemusic.name=Bisukan Musik +setting.sfxvol.name=Volume Suara +setting.mutesound.name=Bisukan Suara +map.maze.name=labirin +map.fortress.name=benteng +map.sinkhole.name=lubang pembuangan +map.caves.name=gua +map.volcano.name=gunung berapi +map.caldera.name=kaldera +map.scorch.name=penghangusan +map.desert.name=gurun +map.island.name=pulau +map.grassland.name=padang rumput +map.tundra.name=tundra +map.spiral.name=spiral +map.tutorial.name=tutorial +keybind.move_x.name=gerak_x +keybind.move_y.name=gerak_y +keybind.select.name=pilih +keybind.break.name=hapus +keybind.shoot.name=tembak +keybind.zoom_hold.name=perbesar_tahan +keybind.zoom.name=perbesar +keybind.menu.name=menu +keybind.pause.name=jeda +keybind.dash.name=berlari +keybind.rotate_alt.name=putar_alt +keybind.rotate.name=putar +mode.waves.name=gelombang +mode.sandbox.name=sandbox +mode.freebuild.name=freebuild +item.stone.name=batu +item.coal.name=batu bara +item.titanium.name=titanium +item.thorium.name=thorium +item.sand.name=pasir +liquid.water.name=air +liquid.lava.name=lahar +liquid.oil.name=minyak +block.door.name=pintu +block.door-large.name=pintu besar +block.conduit.name=saluran +block.pulseconduit.name=saluran cepat +block.liquidrouter.name=router cairan +block.conveyor.name=konveyor +block.router.name=router +block.junction.name=persimpangan jalan +block.liquidjunction.name=persimpangan cairan +block.sorter.name=penyortir +block.smelter.name=peleburan +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.newgame=New Game +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.banned=You are banned on this server. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.trace=Trace Player +text.trace.playername=Player name: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Unique ID: [accent]{0} +text.trace.android=Android Client: [accent]{0} +text.trace.modclient=Custom Client: [accent]{0} +text.trace.totalblocksbroken=Total blocks broken: [accent]{0} +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.trace.lastblockbroken=Last block broken: [accent]{0} +text.trace.totalblocksplaced=Total blocks placed: [accent]{0} +text.trace.lastblockplaced=Last block placed: [accent]{0} +text.invalidid=Invalid client ID! Submit a bug report. +text.server.bans=Bans +text.server.bans.none=No banned players found! +text.server.admins=Admins +text.server.admins.none=No admins found! +text.server.outdated=[crimson]Outdated Server![] +text.server.outdated.client=[crimson]Outdated Client![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[yellow]Custom Build +text.confirmban=Are you sure you want to ban this player? +text.confirmunban=Are you sure you want to unban this player? +text.confirmadmin=Are you sure you want to make this player an admin? +text.confirmunadmin=Are you sure you want to remove admin status from this player? +text.disconnect.data=Failed to load world data! +text.save.difficulty=Difficulty: {0} +text.copylink=Copy Link +text.changelog.title=Changelog +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.multithread.name=Multithreading +setting.minimap.name=Show Minimap +text.keybind.title=Rebind Keys +keybind.block_info.name=block_info +keybind.chat.name=chat +keybind.player_list.name=player_list +keybind.console.name=console +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_ita.properties b/core/assets/bundles/bundle_ita.properties index 02b83f8158..4b02d88130 100644 --- a/core/assets/bundles/bundle_ita.properties +++ b/core/assets/bundles/bundle_ita.properties @@ -1,551 +1,495 @@ -text.about = Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\nOriginariamente era una voce nel [orange]GDL[] Metal Monstrosity Jam.\n\n Crediti:\n - SFX realizzato con [YELLOW]bfxr [] \n - Musica creata da [GREEN]RoccoW[] / trovata su [lime]FreeMusicArchive.org[]\n\n Un ringraziamento speciale a:\n - [coral]MitchellFJN []: esteso test del gioco e feedback\n - [sky]Luxray5474 []: lavorazione della wiki, contributi col codice\n - [lime]Epowerj []: sistema di costruzione del codice, icone\n - Tutti i beta tester su itch.io e Google Play\n -text.credits = Crediti -text.discord = Unisciti sul server discord di mindustry! -text.changes = [SCARLET]Attenzione!\n[]Alcune importanti meccaniche di gioco sono state modificate.\n\n - [accent]I teletrasporti[] ora usano la corrente.\n - [accent]Le fornaci[] e [accent]i crogioli[] ora hanno una capacità massima di oggetti. \n- [accent]I crogioli[] ora richiedono il carbone come combustibile. -text.link.discord.description = la chatroom ufficiale del server discord di Mindustry -text.link.github.description = Codice sorgente del gioco -text.link.dev-builds.description = Build di sviluppo versioni instabili -text.link.trello.description = Scheda ufficiale trello per funzionalità pianificate -text.link.itch.io.description = pagina di itch.io con download per PC e versione web -text.link.google-play.description = Elenco di Google Play Store -text.link.wiki.description = wiki ufficiale di Mindustry -text.linkfail = Impossibile aprire il link! L'URL è stato copiato nella tua bacheca. -text.editor.web = La versione web non supporta l'editor! Scarica il gioco per usarlo. -text.multiplayer.web = Questa versione del gioco non supporta il multiplayer! Per giocare in multiplayer dal tuo browser, usa il link \"versione web multiplayer\" nella pagina itch.io. -text.gameover = Il nucleo è stato distrutto. -text.highscore = [YELLOW]Nuovo record! -text.lasted = Sei durato fino all'onda -text.level.highscore = Migliore: [accent]{0} -text.level.delete.title = Conferma Eliminazione -text.level.delete = Sei sicuro di voler eliminare la mappa \"[arancione]{0}\"? -text.level.select = Selezione del livello -text.level.mode = Modalità di gioco: -text.savegame = Salva -text.loadgame = Carica -text.joingame = Gioca MP -text.newgame = Nuovo gioco -text.quit = Esci -text.about.button = Informazioni -text.name = Nome: -text.public = Pubblico -text.players = {0} giocatori online -text.server.player.host = {0} (host) -text.players.single = {0} giocatori online -text.server.mismatch = Errore nel pacchetto: possibile discrepanza nella versione client / server. Assicurati che tu e l'host abbiate l'ultima versione di Mindustry! -text.server.closing = [accent]Chiusura server ... -text.server.kicked.kick = Sei stato cacciato dal server! -text.server.kicked.invalidPassword = 10468 = Password non valida. -text.server.kicked.clientOutdated = Versione del client obsoleta! Aggiorna il tuo gioco! -text.server.kicked.serverOutdated = Server obsoleto! Chiedi all'host di aggiornare! -text.server.kicked.banned = Sei stato bannato su questo server. -text.server.kicked.recentKick = Sei stato cacciato di recente. Attendi prima di connetterti di nuovo. -text.server.connected = {0} si è connesso -text.server.disconnected = {0} si è disconnesso -text.nohost = Impossibile hostare il server con una mappa personalizzata! -text.host.info = Il pulsante [accent]hos [] ospita un server sulle porte [scarlet]6567[] e [scarlet]656.[] Chiunque sulla stessa [LIGHT_GRAY]connessione wifi o rete locale[] dovrebbe essere in grado di vedere il proprio server nel proprio elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. -text.join.info = Qui è possibile inserire un [accent]IP del server[] a cui connettersi, o scoprire [accento]un server sulla rete locale[] disponibile.\n Sono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco di server globali automatici; se si desidera connettersi a qualcuno tramite IP, è necessario chiedere all'host il proprio IP. -text.hostserver = Server host -text.host = Host -text.hosting = [accento] Apertura del server ... -text.hosts.refresh = Aggiorna -text.hosts.discovering = Scoperta partite LAN -text.server.refreshing = Aggiornamento server -text.hosts.none = [lightgray]Nessuna partita LAN trovata! -text.host.invalid = [scarlet]Impossibile connettersi all'host. -text.server.friendlyfire = Fuoco amico -text.trace = Trace Player -text.trace.playername = Nome del giocatore: [accent]{0} -text.trace.ip = IP: [accent]{0} -text.trace.id = ID univoco: [accent]{0} -text.trace.android = Client Android: [accent] {0} -text.trace.modclient = Cliente personalizzato: [accent]{0} -text.trace.totalblocksbroken = Totale blocchi interrotti: [accent]{0} -text.trace.structureblocksbroken = Blocchi strutturali distrutti: [accent]{0} -text.trace.lastblockbroken = Ultimo blocco distrutto: [accent]{0} -text.trace.totalblocksplaced = Totale blocchi posizionati: [accent]{0} -text.trace.lastblockplaced = Ultimo blocco inserito: [accent]{0} -text.invalidid = ID cliente non valido! Invia una segnalazione di bug. -text.server.bans = Lista Ban -text.server.bans.none = Nessun giocatore bandito trovato! -text.server.admins = Amministratori -text.server.admins.none = Nessun amministratore trovato! -text.server.add = Aggiungi server -text.server.delete = Sei sicuro di voler eliminare questo server? -text.server.hostname = Host: {0} -text.server.edit = Modifica server -text.server.outdated = [crimson]Server obsoleto![] -text.server.outdated.client = [crimson]Client obsoleto![] -text.server.version = [lightgray]Versione: {0} -text.server.custombuild = [yellow] Costruzione personalizzata -text.confirmban = Sei sicuro di voler bandire questo giocatore? -text.confirmunban = Sei sicuro di voler sbloccare questo giocatore? -text.confirmadmin = Sei sicuro di voler rendere questo giocatore un amministratore? -text.confirmunadmin = Sei sicuro di voler rimuovere lo stato di amministratore da questo player? -text.joingame.byip = Unisciti a IP ... -text.joingame.title = Unisciti alla Partita -text.joingame.ip = IP: -text.disconnect = Disconnesso. -text.disconnect.data = Errore nel caricamento i dati del mondo! -text.connecting = [accent]Connessione in corso ... -text.connecting.data = [accent]Caricamento dei dati del mondo ... -text.connectfail = [crimson] Impossibile connettersi al server: [orange] {0} -text.server.port = Porta: -text.server.addressinuse = Indirizzo già in uso! -text.server.invalidport = Numero di porta non valido! -text.server.error = [crimson]Errore nell'hosting del server: [orange] {0} -text.tutorial.back = < Prec -text.tutorial.next = Succ > -text.save.new = Nuovo Salvataggio -text.save.overwrite = Sei sicuro di voler sovrascrivere questo salvataggio? -text.overwrite = Sostituisci -text.save.none = Nessun salvataggio trovato! -text.saveload = [Accent]Salvataggio ... -text.savefail = Salvataggio del gioco non riuscito! -text.save.delete.confirm = Sei sicuro di voler eliminare questo salvataggio? -text.save.delete = Elimina -text.save.export = Esporta Salva -text.save.import.invalid = [orange]Questo salvataggio non è valido! -text.save.import.fail = [crimson]Impossibile importare salvataggio: [orange]{0} -text.save.export.fail = [crimson]Impossibile esportare il salvataggio: [orange]{0} -text.save.import = Importa Salvataggio -text.save.newslot = Salva nome: -text.save.rename = Rinomina -text.save.rename.text = Nuovo nome: -text.selectslot = Seleziona un salvataggio. -text.slot = [accent]Slot {0} -text.save.corrupted = [orang]File di salvataggio danneggiato o non valido! -text.empty = -text.on = Acceso -text.off = Spento -text.save.autosave = Salvataggio automatico: {0} -text.save.map = mappa -text.save.wave = Ondata: -text.save.difficulty = Difficolta: {0} -text.save.date = Ultimo salvataggio: {0} -text.confirm = Conferma -text.delete = Elimina -text.ok = OK -text.open = Apri -text.cancel = Annulla -text.openlink = Apri Link -text.copylink = Copia link -text.back = Indietro -text.quit.confirm = Sei sicuro di voler uscire? -text.changelog.title = Registro modifiche -text.changelog.loading = Ottenere il registro delle modifiche ... -text.changelog.error.android = [orange]Nota che il log delle modifiche non funziona su Android 4.4 e versioni precedenti! Ciò è dovuto a un bug interno di Android. -text.changelog.error = [scarlet]Errore durante il recupero del changelog! Controlla la tua connessione Internet. -text.changelog.current = [yellow][[Current version] -text.changelog.latest = [orange][[Latest version] -text.loading = [accent]Caricamento in corso ... -text.wave = [orange]Onda {0} -text.wave.waiting = Onda in {0} -text.waiting = In attesa... -text.enemies = {0} Nemici -text.enemies.single = {0} Nemico -text.loadimage = Carica immagine -text.saveimage = Salva Immagine -text.oregen = Generazione dei minerali -text.editor.badsize = [orange]Dimensioni dell'immagine non valide![]\n Dimensioni della mappa valide: {0} -text.editor.errorimageload = Errore durante il caricamento del file immagine:\n [orange]{0} -text.editor.errorimagesave = Errore durante il salvataggio del file immagine:\n [orange]{0} -text.editor.generate = Genera -text.editor.resize = Zomma o \nRiduci -text.editor.loadmap = Carica\nmappa -text.editor.savemap = Salva\nla mappa -text.editor.loadimage = Carica\nimmagine -text.editor.saveimage = Salva\nImmagine -text.editor.unsaved = [scarlet]Hai modifiche non salvate![]\nSei sicuro di voler uscire? -text.editor.brushsize = Dimensione del pennello: {0} -text.editor.noplayerspawn = Questa mappa non ha lo spawnpoint del giocatore! -text.editor.manyplayerspawns = Le mappe non possono avere più di un punto di spawn di un giocatore! -text.editor.manyenemyspawns = Non puoi avere più di {0} spawn nemici! -text.editor.resizemap = Ridimensiona la mappa -text.editor.resizebig = [Scarlet]Attenzione!\n[]Le mappe più grandi di 256 unità potrebbero causare del lag oltre ad essere instabili. -text.editor.mapname = Nome Mappa: -text.editor.overwrite = [Accent]Attenzione!\nQuesto sovrascrive una mappa esistente. -text.editor.failoverwrite = [crimson]Impossibile sovrascrivere la mappa di default! -text.editor.selectmap = Seleziona una mappa da caricare: -text.width = Larghezza: -text.height = Altezza: -text.randomize = Randomizza -text.apply = Applicare -text.update = Aggiorna -text.menu = Menu -text.play = Gioca -text.load = Carica -text.save = Salva -text.language.restart = Riavvia il gioco affinché il cambiamento della lingua abbia effetto. -text.settings.language = Lingua -text.settings = Impostazioni -text.tutorial = Lezioni -text.editor = Editor -text.mapeditor = Editor delle mappe -text.donate = Dona -text.settings.reset = Resetta Alle Impostazioni Predefinite -text.settings.controls = Controlli -text.settings.game = Gioco -text.settings.sound = Suono -text.settings.graphics = Grafica -text.upgrades = Miglioramenti -text.purchased = [LIME]Creato! -text.weapons = Armi -text.paused = In pausa -text.respawn = Rinascita in -text.info.title = [Accent]Informazioni -text.error.title = [crimson]Si è verificato un errore -text.error.crashmessage = [SCARLET]Si è verificato un errore imprevisto che ha causato un arresto anomalo.[] Si prega di segnalare le circostanze esatte in cui questo errore si è verificato allo sviluppatore:\n[ORANGE]anukendev@gmail.com[] -text.error.crashtitle = Si è verificato un errore -text.mode.break = Modalità di interruzione: {0} -text.mode.place = Modalità luogo: {0} -placemode.hold.name = linea -placemode.areadelete.name = area -placemode.touchdelete.name = toccare -placemode.holddelete.name = trattieni -placemode.none.name = nessuno -placemode.touch.name = toccare -placemode.cursor.name = cursore -text.blocks.extrainfo = [accent]informazioni extra sui blocchi: -text.blocks.blockinfo = Informazioni sul blocco -text.blocks.powercapacity = Capacità energetica -text.blocks.powershot = Danno/Colpo -text.blocks.powersecond = Energia/Secondo -text.blocks.powerdraindamage = Consumo/Danno -text.blocks.shieldradius = Raggio dello scudo -text.blocks.itemspeedsecond = Velocita Oggetti/Secondo -text.blocks.range = Gamma -text.blocks.size = Grandezza -text.blocks.powerliquid = Energia/Liquido -text.blocks.maxliquidsecond = Max liquido/Secondo -text.blocks.liquidcapacity = Capacità del liquido -text.blocks.liquidsecond = Liquido/Secondo -text.blocks.damageshot = Danni colpo -text.blocks.ammocapacity = Capacità del caricatore -text.blocks.ammo = Munizioni -text.blocks.ammoitem = Munizioni/Oggetto -text.blocks.maxitemssecond = Oggetti massimi/secondo -text.blocks.powerrange = Raggio Energia -text.blocks.lasertilerange = Raggio piastrelle laser -text.blocks.capacity = Capacità -text.blocks.itemcapacity = Capacità oggetto -text.blocks.maxpowergenerationsecond = Massima Energia Generata/secondo -text.blocks.powergenerationsecond = Energia generata/secondo -text.blocks.generationsecondsitem = Generazione secondi/oggetto -text.blocks.input = Ingresso -text.blocks.inputliquid = Ingresso del liquido -text.blocks.inputitem = Ingresso Oggetto -text.blocks.output = Uscita -text.blocks.secondsitem = Secondi/item -text.blocks.maxpowertransfersecond = Massimo trasferimento di potenza/secondo -text.blocks.explosive = Altamente esplosivo! -text.blocks.repairssecond = Ripara/secondo -text.blocks.health = Salute -text.blocks.inaccuracy = inesattezza -text.blocks.shots = Colpi -text.blocks.shotssecond = Colpi/secondo -text.blocks.fuel = Carburante -text.blocks.fuelduration = Durata del carburante -text.blocks.maxoutputsecond = Uscita max/secondo -text.blocks.inputcapacity = Capacità di ingresso -text.blocks.outputcapacity = Capacità di uscita -text.blocks.poweritem = Energia/Oggetto -text.placemode = Place Mode -text.breakmode = Modalità di interruzione -text.health = Salutee -setting.difficulty.easy = facile -setting.difficulty.normal = medio -setting.difficulty.hard = difficile -setting.difficulty.insane = Folle -setting.difficulty.purge = Epurazione -setting.difficulty.name = Difficoltà: -setting.screenshake.name = Screen Shake -setting.smoothcam.name = Smooth Camera -setting.indicators.name = Indicatori nemici -setting.effects.name = Visualizza effetti -setting.sensitivity.name = Sensibilità del controllore. -setting.saveinterval.name = Intervallo di salvataggio automatico -setting.seconds = {0} Secondi -setting.fullscreen.name = Schermo Intero -setting.multithread.name = multithreading -setting.fps.name = Mostra FPS -setting.vsync.name = Sincronizzazione Verticale -setting.lasers.name = Mostra Energia Dei Laser -setting.healthbars.name = Mostra barra della salute delle entità -setting.pixelate.name = Schermo Pixelate -setting.musicvol.name = Volume Musica -setting.mutemusic.name = Musica muta -setting.sfxvol.name = Volume SFX -setting.mutesound.name = Suono muto -map.maze.name = labirinto -map.fortress.name = fortezza -map.sinkhole.name = dolina -map.caves.name = grotte -map.volcano.name = vulcano -map.caldera.name = caldera -map.scorch.name = bruciatura -map.desert.name = Deserto -map.island.name = Isola -map.grassland.name = Prateria -map.tundra.name = Tundra -map.spiral.name = spirale -map.tutorial.name = Tutorial -tutorial.intro.text = [yellow]Benvenuti nel tutorial.[] Per iniziare, premere 'succ'. -tutorial.moveDesktop.text = Per spostarsi, utilizza i tasti [orange][[WASD][] . Tenere premuto [orange]shift []per correre. Tenere premuto [orange]CTRL[] mentre si utilizza la [orange]rotella del mouse[] per ingrandire o ridurre lo zoom. -tutorial.shoot.text = Usa il mouse per mirare, tieni premuto [orange]tasto sinistro del mouse[] per sparare. Fai uun po' di pratica con quest' [yellow]obiettivo[]. -tutorial.moveAndroid.text = Per spostare la vista, trascina un dito sullo schermo. Pizzica e trascina per ingrandire o ridurre. -tutorial.placeSelect.text = Prova a selezionare un [yellow]nastro trasportatore[] dal menu dei blocchi in basso a destra. -tutorial.placeConveyorDesktop.text = Utilizza la [orange]rotellina di scorrimento[] per ruotare il nastro trasportatore in modo che sia rivolto verso [orange]in avanti[], quindi posizionarlo nella [yellow]posizione contrassegnata[] utilizzando il [orange]tasto sinistro del mouse[]. -tutorial.placeConveyorAndroid.text = Utilizzare il pulsante [orange]tasto di rotazione[] per ruotare il trasportatore in modo che sia rivolto [orange]in avanti[], trascinalo in posizione con un dito, quindi posizionalo nella [yellow]posizione contrassegnata[] utilizzando [orange]segno di spunta[] -tutorial.placeConveyorAndroidInfo.text = In alternativa, puoi premere l'icona mirino in basso a sinistra per passare alla [orange] touch mode[] e posiziona i blocchi toccando sullo schermo. In modalità touch, i blocchi possono essere ruotati con la freccia in basso a sinistra. Premi [yellow]avanti[] per provarlo. -tutorial.placeDrill.text = Ora, seleziona e posiziona un [yellow]trapano per pietra[] nella posizione contrassegnata. -tutorial.blockInfo.text = Se vuoi saperne di più su un blocco, puoi toccare il [orange]punto interrogativo[] in alto a destra per leggere la sua descrizione. -tutorial.deselectDesktop.text = Puoi deselezionare un blocco usando [orange]tasto destro del mouse[]. -tutorial.deselectAndroid.text = È possibile deselezionare un blocco premendo il tasto [orange]X[]. -tutorial.drillPlaced.text = Il trapano ora produrrà [yellow]pietra,[] la manderà sul nastro trasportatore, quindi la sposterà nel [yellow]nucleo[]. -tutorial.drillInfo.text = I minerali differenti hanno bisogno di trapani diversi. La pietra richiede il trapano di pietra, il ferro richiede il trapano di ferro, ecc. -tutorial.drillPlaced2.text = Spostando gli oggetti nel nucleo li metti nell' [yellow]inventario[], in alto a sinistra. Piazzare i blocchi usa gli oggetti dal tuo inventario. -tutorial.moreDrills.text = Puoi collegare molti trapani e trasportatori insieme, in questo modo. -tutorial.deleteBlock.text = È possibile eliminare i blocchi facendo clic sul [orange]pulsante destro del mouse[] sul blocco che si desidera eliminare. Prova a eliminare questo trasportatore. -tutorial.deleteBlockAndroid.text = È possibile eliminare i blocchi [orange]selezionandoli col mirino[] nel menu della [orange]modalità pausa[] in basso a sinistra e toccando un blocco. Prova a eliminare questo trasportatore. -tutorial.placeTurret.text = Ora, seleziona e posiziona una [yellow]torretta[] nella [yellow]posizione contrassegnata[]. -tutorial.placedTurretAmmo.text = Questa torretta ora accetta [yellow]munizioni[] dal trasportatore. Puoi vedere quante munizioni ha al passaggio del mouse [green]barra verde[]. -tutorial.turretExplanation.text = Le torrette spareranno automaticamente al nemico più vicino nel raggio d'azione, a patto che abbiano munizioni sufficienti. -tutorial.waves.text = Ogni [yellow]60[] secondi, un'ondata di [coral]nemici[] si genera in posizioni specifiche e tenta di distruggere il nucleo. -tutorial.coreDestruction.text = Il tuo obiettivo è difendere [yellow]il nucleo[]. Se il nucleo viene distrutto, tu [coral]perdi la partita[]. -tutorial.pausingDesktop.text = Se hai bisogno di fare una pausa, premi il [orange]pulsante di pausa[] in alto a sinistra per mettere in pausa il gioco. Puoi ancora selezionare e posizionare i blocchi mentre sei in pausa, ma non puoi muoverti o sparare -tutorial.pausingAndroid.text = Se hai bisogno di fare una pausa, premi il [orange]pulsante di pausa[] in alto a sinistra per mettere in pausa il gioco. Puoi ancora rompere e posizionare i blocchi mentre sei in pausa. -tutorial.purchaseWeapons.text = Puoi acquistare nuove [yellow]armi[] per il tuo mech aprendo il menu di aggiornamenti in basso a sinistra. -tutorial.switchWeapons.text = Cambia le armi facendo clic sulla sua icona in basso a sinistra o usando i numeri [orange][[1-9][]. -tutorial.spawnWave.text = Ecco un'ondata ora. Distruggili. -tutorial.pumpDesc.text = Nelle onde successive, potrebbe essere necessario utilizzare le [yellow]pompe[] per distribuire i liquidi per i generatori o gli estrattori. -tutorial.pumpPlace.text = Le pompe funzionano in modo simile ai trapani, tranne per il fatto che producono liquidi anziché oggetti. Prova a posizionare una pompa sull' [yellow]petrolio evidenziato[]. -tutorial.conduitUse.text = Ora posiziona una [orange]conduttura[] -tutorial.conduitUse2.text = E alcuni altri ... -tutorial.conduitUse3.text = E alcuni altri ... -tutorial.generator.text = Ora, posizionare un [orange]generatore a combustione[] all'estremità del condotto. -tutorial.generatorExplain.text = Questo generatore ora creerà [yellow]corrente[] dall'petrolio. -tutorial.lasers.text = La potenza è distribuita usando i [yellow]laser energetici[]. Ruota e posizionane uno qui. -tutorial.laserExplain.text = Il generatore ora trasferirà l'energia nel blocco laser. Un raggio [yellow]opaco[] indica che sta trasmettendo corrente e un raggio [yellow]trasparente[] significa che non la sta strasmettendo. -tutorial.laserMore.text = Puoi controllare quanta energia ha un blocco passandoci sopra e controllando la barra [yellow]gialla[] in alto. -tutorial.healingTurret.text = Questo laser può essere utilizzato per alimentare una [lime]torretta di riparazione[]. Mettine una qui. -tutorial.healingTurretExplain.text = Finché ha energia, questa torretta [lime]riparerà i blocchi vicini.[] Durante la riproduzione del gioco, assicurati di averne una nella tua base il più rapidamente possibile! -tutorial.smeltery.text = Molti blocchi richiedono [orange]acciaio[] da produrre, che richiede una [orange] fonderia[] per la produzione. Mettine una qui. -tutorial.smelterySetup.text = Questa fonderia produrrà ora [orange]acciaio[] dal ferro in ingresso, usando il carbone come combustibile. -tutorial.tunnelExplain.text = Si noti inoltre che gli oggetti passano attraverso un[orange]tunnel[] e emergono dall'altra parte, passando attraverso il blocco di pietra. Tieni presente che i tunnel possono attraversare fino a 2 blocchi. -tutorial.end.text = E questo conclude il tutorial! In bocca al lupo! -text.keybind.title = Configurazione Tasti -keybind.move_x.name = move_x -keybind.move_y.name = move_y -keybind.select.name = seleziona -keybind.break.name = rompere -keybind.shoot.name = sparare -keybind.zoom_hold.name = zoom_hold -keybind.zoom.name = zoom -keybind.block_info.name = Informazioni blocco -keybind.menu.name = menu -keybind.pause.name = pausa -keybind.dash.name = corsa -keybind.chat.name = Chat -keybind.player_list.name = lista_giocatori -keybind.console.name = console -keybind.rotate_alt.name = rotate_alt -keybind.rotate.name = Ruotare -keybind.weapon_1.name = arma_1 -keybind.weapon_2.name = arma_2 -keybind.weapon_3.name = arma_3 -keybind.weapon_4.name = arma_4 -keybind.weapon_5.name = arma_5 -keybind.weapon_6.name = arma_6 -mode.text.help.title = Descrizione delle modalità -mode.waves.name = onde -mode.waves.description = modalità normale. risorse limitate e onde in entrata automatiche. -mode.sandbox.name = Sandbox -mode.sandbox.description = risorse infinite e nessun timer per le onde. -mode.freebuild.name = freebuild -mode.freebuild.description = risorse limitate e nessun timer per le onde. -upgrade.standard.name = Standard -upgrade.standard.description = Il mech standard. -upgrade.blaster.name = blaster -upgrade.blaster.description = Spara un proiettile lento, debole. -upgrade.triblaster.name = triblaster -upgrade.triblaster.description = Spara 3 proiettili a diffusione. -upgrade.clustergun.name = clustergun -upgrade.clustergun.description = Spara delle imprecise granate esplosive. -upgrade.beam.name = cannone a raggi -upgrade.beam.description = Spara un raggio laser penetrante a lungo raggio. -upgrade.vulcan.name = Vulcano -upgrade.vulcan.description = Spara una raffica di proiettili veloci. -upgrade.shockgun.name = shockgun -upgrade.shockgun.description = Spara a una devastante esplosione di shrapnel carichi. -item.stone.name = pietra -item.iron.name = ferro -item.coal.name = carbone -item.steel.name = acciaio -item.titanium.name = titanio -item.dirium.name = diridio -item.uranium.name = uranio -item.sand.name = sabbia -liquid.water.name = acqua -liquid.plasma.name = Plasma -liquid.lava.name = lava -liquid.oil.name = petrolio -block.weaponfactory.name = fabbrica d'armi -block.weaponfactory.fulldescription = Utilizzata per creare armi per il giocatore mech. Clicca per usare. Prende automaticamente le risorse dal core. -block.air.name = aria -block.blockpart.name = blockpart -block.deepwater.name = acque profonde -block.water.name = acqua -block.lava.name = lava -block.oil.name = petrolio -block.stone.name = pietra -block.blackstone.name = pietra nera -block.iron.name = ferro -block.coal.name = carbone -block.titanium.name = titanio -block.uranium.name = uranio -block.dirt.name = terra -block.sand.name = sabbia -block.ice.name = ghiaccio -block.snow.name = neve -block.grass.name = Erba -block.sandblock.name = blocco di sabbia -block.snowblock.name = blocco di neve -block.stoneblock.name = blocco di pietra -block.blackstoneblock.name = blocco di pietra nera -block.grassblock.name = blocco d'erba -block.mossblock.name = blocco di muschio -block.shrub.name = arbusto -block.rock.name = roccia -block.icerock.name = giaccio -block.blackrock.name = roccia nera -block.dirtblock.name = blocco di terra -block.stonewall.name = muro di pietra -block.stonewall.fulldescription = Un blocco difensivo poco costoso. Utile per proteggere il nucleo e le torrette nelle prime ondate. -block.ironwall.name = muro di ferro -block.ironwall.fulldescription = Un blocco difensivo di base. Fornisce protezione dai nemici. -block.steelwall.name = muro d'acciaio -block.steelwall.fulldescription = Un blocco difensivo standard. protezione adeguata dai nemici. -block.titaniumwall.name = muro di titanio -block.titaniumwall.fulldescription = Un forte blocco difensivo. Fornisce protezione dai nemici. -block.duriumwall.name = muro di diridio -block.duriumwall.fulldescription = Un blocco difensivo molto forte. Fornisce protezione dai nemici. -block.compositewall.name = muro composito -block.steelwall-large.name = grande muro di acciaio -block.steelwall-large.fulldescription = Un blocco difensivo standard. Si estende su più tessere. -block.titaniumwall-large.name = grande muro di titanio -block.titaniumwall-large.fulldescription = Un forte blocco difensivo. Si estende su più tessere. -block.duriumwall-large.name = grande muro di diridio -block.duriumwall-large.fulldescription = Un blocco difensivo molto forte. Si estende su più tessere. -block.titaniumshieldwall.name = muro schermato -block.titaniumshieldwall.fulldescription = Un forte blocco difensivo, con uno scudo incorporato extra. Richiede energia. Utilizza l'energia per assorbire i proiettili nemici. Si consiglia di utilizzare i booster di energia per fornire energia a questo blocco. -block.repairturret.name = torretta di riparazione -block.repairturret.fulldescription = Ripara i blocchi danneggiati vicini nel raggio di azione a un ritmo lento. Utilizza piccole quantità di energia. -block.megarepairturret.name = torretta di riparazione II -block.megarepairturret.fulldescription = Ripara i blocchi vicini danneggiati nel raggio di portata a ritmo moderato. Usa il potere. -block.shieldgenerator.name = generatore di scudi -block.shieldgenerator.fulldescription = Un blocco difensivo avanzato. Fa da scudo per tutti i blocchi in un raggio dalla posizione. Utilizza l'energia a una velocità ridotta quando è inattivo, ma scarica rapidamente energia sul contatto con i proiettili. -block.door.name = porta -block.door.fulldescription = Un blocco che può essere aperto e chiuso toccandolo. -block.door-large.name = grande porta -block.door-large.fulldescription = Un blocco che può essere aperto e chiuso toccandolo. -block.conduit.name = Condotto -block.conduit.fulldescription = Blocco di trasporto liquido di base. Funziona come un trasportatore, ma con liquidi. Ideale per pompe o altri condotti. Può essere usato come un ponte sui liquidi per nemici e giocatori. -block.pulseconduit.name = condotto di impulso -block.pulseconduit.fulldescription = Blocco di trasporto di liquidi avanzato. Trasporta i liquidi più velocemente e immagazzina più dei condotti standard. -block.liquidrouter.name = router liquido -block.liquidrouter.fulldescription = Funziona in modo simile a un router. Accetta input liquidi da un lato e li invia agli altri lati. Utile per separare il liquido da un singolo condotto in più condotti. -block.conveyor.name = trasportatore -block.conveyor.fulldescription = Blocco di trasporto basico. Sposta gli oggetti in avanti e li deposita automaticamente in torrette o crafters. Ruotabile. Può essere usato come un ponte sui liquidi per nemici e giocatori. -block.steelconveyor.name = trasportatore d'acciaio -block.steelconveyor.fulldescription = Blocco avanzato di trasporto. Sposta gli oggetti più velocemente rispetto ai trasportatori standard. -block.poweredconveyor.name = trasportatore di impulsi -block.poweredconveyor.fulldescription = Il blocco di trasporto di ultima generazione. Sposta gli oggetti più velocemente dei trasportatori in acciaio. -block.router.name = router -block.router.fulldescription = Accetta elementi da una direzione e li invia a 3 altre direzioni. Può anche memorizzare una certa quantità di oggetti. Utile per dividere i materiali da un trapano a più torrette. -block.junction.name = giunzione -block.junction.fulldescription = Funziona come un ponte per due nastri trasportatori che la attraversono. Utile in situazioni con due diversi trasportatori che trasportano materiali diversi in luoghi diversi. -block.conveyortunnel.name = tunnel di trasporto -block.conveyortunnel.fulldescription = Trasporta oggetti sotto blocchi. Per utilizzare, posizionare un tunnel che conduce nel blocco da scavare sotto il tunnel e uno sull'altro lato. Assicurarsi che entrambe le gallerie siano rivolte in direzioni opposte, cioè verso i blocchi in cui vengono immesse o in uscita. -block.liquidjunction.name = giunzione liquida -block.liquidjunction.fulldescription = Funziona come un ponte per due condotti di attraversamento. Utile in situazioni con due condotti diversi che trasportano liquidi diversi in luoghi diversi. -block.liquiditemjunction.name = giunzione di oggetti liquidi -block.liquiditemjunction.fulldescription = Funziona come un ponte per attraversare condutture e trasportatori. -block.powerbooster.name = power booster -block.powerbooster.fulldescription = Distribuisce l'energia a tutti i blocchi entro il suo raggio. -block.powerlaser.name = laser energetico -block.powerlaser.fulldescription = Crea un laser che trasmette energia al blocco di fronte ad esso. Non genera alcuna energia. Ideale per generatori o altri laser. -block.powerlaserrouter.name = router laser -block.powerlaserrouter.fulldescription = Laser che distribuisce la potenza in tre direzioni contemporaneamente. Utile in situazioni in cui è necessario alimentare più blocchi da un generatore. -block.powerlasercorner.name = angolo laser -block.powerlasercorner.fulldescription = Laser che distribuisce la potenza in due direzioni contemporaneamente. Utile in situazioni in cui è necessario alimentare più blocchi da un generatore e un router è impreciso. -block.teleporter.name = teletrasporto -block.teleporter.fulldescription = Blocco avanzato di trasporto dell'elemento. I teletrasportatori immettono gli oggetti ad altri teletrasportatori dello stesso colore. Non fa nulla se non esistono teletrasportatori dello stesso colore. Se esistono più teletrasporti dello stesso colore, ne viene selezionato uno casuale. Usa l'energia. Tocca per cambiare colore. -block.sorter.name = sorter -block.sorter.fulldescription = Ordina l'oggetto per tipo di materiale. Il materiale da accettare è indicato dal colore nel blocco. Tutti gli articoli che corrispondono al materiale di ordinamento vengono emessi in avanti, tutto il resto viene emesso a sinistra e a destra. -block.core.name = Centro -block.pump.name = pompa -block.pump.fulldescription = Pompa di liquidi da un blocco sorgente - di solito acqua, lava o petrolio. Emette liquido nei condotti nelle vicinanze. -block.fluxpump.name = pompaflux -block.fluxpump.fulldescription = Una versione avanzata della pompa. Memorizza più liquido e pompa il liquido più velocemente. -block.smelter.name = fonderia -block.smelter.fulldescription = Il blocco di lavorazione essenziale. Quando immesso 1 ferro e 1 carbone come combustibile, emette un acciaio. Si consiglia di inserire ferro e carbone su diverse cinghie per evitare l'intasamento. -block.crucible.name = crogiuolo -block.crucible.fulldescription = Un blocco di lavorazione avanzato. Immettendo 1 titanio, 1 acciaio e 1 carbone come combustibile, emette un diridio. Si consiglia di inserire carbone, acciaio e titanio su nastri diversi per evitare l'intasamento. -block.coalpurifier.name = estrattore di carbone -block.coalpurifier.fulldescription = Un blocco estrattore di base. Emette carbone quando viene fornito con grandi quantità di acqua e pietra. -block.titaniumpurifier.name = estrattore di titanio -block.titaniumpurifier.fulldescription = Un blocco estrattore standard. Produce il titanio quando viene fornito con grandi quantità di acqua e ferro. -block.oilrefinery.name = raffineria d'petrolio -block.oilrefinery.fulldescription = Affina grandi quantità di petrolio in oggetti di carbone. Utile per alimentare torrette a base di carbone quando le vene del carbone scarseggiano. -block.stoneformer.name = forma pietre -block.stoneformer.fulldescription = Solidifica la lava producendo pietra. Utile per produrre enormi quantità di pietra per depuratori di carbone. -block.lavasmelter.name = fonderia a lava -block.lavasmelter.fulldescription = Usa la lava per convertire il ferro in acciaio. Un'alternativa alle smelterie. Utile in situazioni in cui il carbone è scarso. -block.stonedrill.name = trapano di pietra -block.stonedrill.fulldescription = Il trapano essenziale. Se posizionato su delle piastrelle di pietra, emette una pietra a un ritmo lento indefinitamente. -block.irondrill.name = trapano di ferro -block.irondrill.fulldescription = Un trapano di base. Quando viene posizionato su delle piastrelle con il minerale ferro, emette il ferro a un ritmo lento indefinitamente. -block.coaldrill.name = trivella di carbone -block.coaldrill.fulldescription = Un trapano di base. Se posizionato su delle piastrelle di carbone, produce a tempo indeterminato il carbone a un ritmo lento. -block.uraniumdrill.name = trapano all'uranio -block.uraniumdrill.fulldescription = Un trapano avanzato. Se posizionato su delel piastrelle con dell'uranio, emette l'uranio a un ritmo lento indefinitamente. -block.titaniumdrill.name = trapano in titanio -block.titaniumdrill.fulldescription = Un trapano avanzato. Se posizionato su delle piastrelle di titanio, emette il titanio a un ritmo lento indefinitamente. -block.omnidrill.name = omnidrill -block.omnidrill.fulldescription = L'ultimo trapano. Trapanerà qualsiasi minerale su cui è posizionato ad un ritmo rapido. -block.coalgenerator.name = generatore di carbone -block.coalgenerator.fulldescription = Il generatore essenziale. Genera potenza dal carbone. Emette potenza come laser sui suoi 4 lati. -block.thermalgenerator.name = generatore termico -block.thermalgenerator.fulldescription = Genera energia dalla lava. Emette energia come laser sui suoi 4 lati. -block.combustiongenerator.name = generatore a combustione -block.combustiongenerator.fulldescription = Genera energia dall'petrolio. Emette energia come laser sui suoi 4 lati. -block.rtgenerator.name = Generatore RTG -block.rtgenerator.fulldescription = Genera piccole quantità di energia dal decadimento radioattivo dell'uranio. Emette potenza come laser sui suoi 4 lati. -block.nuclearreactor.name = reattore nucleare -block.nuclearreactor.fulldescription = Una versione avanzata del Generatore RTG e il massimo generatore di energia. Genera potenza dall'uranio. Richiede un raffreddamento costante dell'acqua. Altamente volatile; esploderà violentemente se vengono fornite quantità insufficienti di refrigerante. -block.turret.name = torretta -block.turret.fulldescription = Una torretta semplice ed economica. Usa la pietra per le munizioni. Ha un raggio leggermente superiore rispetto alla doppia torretta. -block.doubleturret.name = doppia torretta -block.doubleturret.fulldescription = Una versione leggermente più potente della torretta. Usa la pietra per le munizioni. Fa molto più danni, ma ha un raggio più basso. Spara due proiettili. -block.machineturret.name = torretta di gattling -block.machineturret.fulldescription = Una torretta standard a tutto tondo. Usa il ferro per le munizioni. Ha una velocità di fuoco veloce con danni decenti. -block.shotgunturret.name = torretta di splitter -block.shotgunturret.fulldescription = Una torretta standard. Usa il ferro per le munizioni. Spara una diffusione di 7 proiettili. Gittata inferiore, ma maggiore danno inflitto rispetto alla torretta gattling. -block.flameturret.name = lanciafiamme -block.flameturret.fulldescription = Torretta avanzata a distanza ravvicinata. Usa carbone per munizioni. Ha una portata molto bassa, ma un danno molto alto. Buono per luoghi chiusi. Consigliato per essere usato dietro i muri. -block.sniperturret.name = torretta ellettromagnetica -block.sniperturret.fulldescription = Torretta avanzata a lungo raggio. Utilizza l'acciaio come munizioni. Danno molto alto, ma bassa velocità di fuoco. Costoso da usare, ma può essere posizionato lontano dalle linee nemiche a causa della sua portata. -block.mortarturret.name = torretta di sfogo -block.mortarturret.fulldescription = Torretta a getto d'acqua avanzato a bassa precisione. Usa carbone per munizioni. Spara una raffica di proiettili che esplodono in shrapnel. Utile per grandi folle di nemici. -block.laserturret.name = torretta laser -block.laserturret.fulldescription = Avanzata torretta a bersaglio singolo. Usa l'energia Buona torretta a medio raggio a tutto tondo. Ingaggio singolo. Non manca mai il bersaglio. -block.waveturret.name = Torretta tesla -block.waveturret.fulldescription = Torretta multi-target avanzata. Usa l'energia. Gamma media Non manca mai. Danno basso, ma può colpire più nemici contemporaneamente con dei fulmini a catena. -block.plasmaturret.name = torretta a plasma -block.plasmaturret.fulldescription = Versione altamente avanzata del lanciafiamme. Usa il carbone come munizione. Danno molto alto, da basso a medio raggio. -block.chainturret.name = torretta a catena -block.chainturret.fulldescription = L'ultima torretta a fuoco rapido. Usa l'uranio come munizione. Spara grossi proiettili ad un alto tasso di fuoco. Gamma media Si estende su più tessere. Estremamente duro. -block.titancannon.name = cannone di titano -block.titancannon.fulldescription = L'ultima torretta a lungo raggio. Usa l'uranio come munizione. Spara grossi proiettili di schizzi a una velocità media di fuoco. Lungo raggio. Si estende su più tessere. Estremamente duro. -block.playerspawn.name = spawngiocatore -block.enemyspawn.name = spawnnemico +text.about=Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\nOriginariamente era una voce nel [orange]GDL[] Metal Monstrosity Jam.\n\n Crediti:\n - SFX realizzato con [YELLOW]bfxr [] \n - Musica creata da [GREEN]RoccoW[] / trovata su [lime]FreeMusicArchive.org[]\n\n Un ringraziamento speciale a:\n - [coral]MitchellFJN []: esteso test del gioco e feedback\n - [sky]Luxray5474 []: lavorazione della wiki, contributi col codice\n - [lime]Epowerj []: sistema di costruzione del codice, icone\n - Tutti i beta tester su itch.io e Google Play\n +text.credits=Crediti +text.discord=Unisciti sul server discord di mindustry! +text.link.discord.description=la chatroom ufficiale del server discord di Mindustry +text.link.github.description=Codice sorgente del gioco +text.link.dev-builds.description=Build di sviluppo versioni instabili +text.link.trello.description=Scheda ufficiale trello per funzionalità pianificate +text.link.itch.io.description=pagina di itch.io con download per PC e versione web +text.link.google-play.description=Elenco di Google Play Store +text.link.wiki.description=wiki ufficiale di Mindustry +text.linkfail=Impossibile aprire il link! L'URL è stato copiato nella tua bacheca. +text.editor.web=La versione web non supporta l'editor! Scarica il gioco per usarlo. +text.multiplayer.web=Questa versione del gioco non supporta il multiplayer! Per giocare in multiplayer dal tuo browser, usa il link "versione web multiplayer" nella pagina itch.io. +text.gameover=Il nucleo è stato distrutto. +text.highscore=[YELLOW]Nuovo record! +text.lasted=Sei durato fino all'onda +text.level.highscore=Migliore: [accent]{0} +text.level.delete.title=Conferma Eliminazione +text.level.select=Selezione del livello +text.level.mode=Modalità di gioco: +text.savegame=Salva +text.loadgame=Carica +text.joingame=Gioca MP +text.newgame=Nuovo gioco +text.quit=Esci +text.about.button=Informazioni +text.name=Nome: +text.players={0} giocatori online +text.players.single={0} giocatori online +text.server.mismatch=Errore nel pacchetto: possibile discrepanza nella versione client / server. Assicurati che tu e l'host abbiate l'ultima versione di Mindustry! +text.server.closing=[accent]Chiusura server ... +text.server.kicked.kick=Sei stato cacciato dal server! +text.server.kicked.invalidPassword=10468 = Password non valida. +text.server.kicked.clientOutdated=Versione del client obsoleta! Aggiorna il tuo gioco! +text.server.kicked.serverOutdated=Server obsoleto! Chiedi all'host di aggiornare! +text.server.kicked.banned=Sei stato bannato su questo server. +text.server.kicked.recentKick=Sei stato cacciato di recente. Attendi prima di connetterti di nuovo. +text.server.connected={0} si è connesso +text.server.disconnected={0} si è disconnesso +text.nohost=Impossibile hostare il server con una mappa personalizzata! +text.host.info=Il pulsante [accent]hos [] ospita un server sulle porte [scarlet]6567[] e [scarlet]656.[] Chiunque sulla stessa [LIGHT_GRAY]connessione wifi o rete locale[] dovrebbe essere in grado di vedere il proprio server nel proprio elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. +text.join.info=Qui è possibile inserire un [accent]IP del server[] a cui connettersi, o scoprire [accento]un server sulla rete locale[] disponibile.\n Sono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco di server globali automatici; se si desidera connettersi a qualcuno tramite IP, è necessario chiedere all'host il proprio IP. +text.hostserver=Server host +text.host=Host +text.hosting=[accento] Apertura del server ... +text.hosts.refresh=Aggiorna +text.hosts.discovering=Scoperta partite LAN +text.server.refreshing=Aggiornamento server +text.hosts.none=[lightgray]Nessuna partita LAN trovata! +text.host.invalid=[scarlet]Impossibile connettersi all'host. +text.server.friendlyfire=Fuoco amico +text.trace=Trace Player +text.trace.playername=Nome del giocatore: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=ID univoco: [accent]{0} +text.trace.android=Client Android: [accent] {0} +text.trace.modclient=Cliente personalizzato: [accent]{0} +text.trace.totalblocksbroken=Totale blocchi interrotti: [accent]{0} +text.trace.structureblocksbroken=Blocchi strutturali distrutti: [accent]{0} +text.trace.lastblockbroken=Ultimo blocco distrutto: [accent]{0} +text.trace.totalblocksplaced=Totale blocchi posizionati: [accent]{0} +text.trace.lastblockplaced=Ultimo blocco inserito: [accent]{0} +text.invalidid=ID cliente non valido! Invia una segnalazione di bug. +text.server.bans=Lista Ban +text.server.bans.none=Nessun giocatore bandito trovato! +text.server.admins=Amministratori +text.server.admins.none=Nessun amministratore trovato! +text.server.add=Aggiungi server +text.server.delete=Sei sicuro di voler eliminare questo server? +text.server.hostname=Host: {0} +text.server.edit=Modifica server +text.server.outdated=[crimson]Server obsoleto![] +text.server.outdated.client=[crimson]Client obsoleto![] +text.server.version=[lightgray]Versione: {0} +text.server.custombuild=[yellow] Costruzione personalizzata +text.confirmban=Sei sicuro di voler bandire questo giocatore? +text.confirmunban=Sei sicuro di voler sbloccare questo giocatore? +text.confirmadmin=Sei sicuro di voler rendere questo giocatore un amministratore? +text.confirmunadmin=Sei sicuro di voler rimuovere lo stato di amministratore da questo player? +text.joingame.title=Unisciti alla Partita +text.joingame.ip=IP: +text.disconnect=Disconnesso. +text.disconnect.data=Errore nel caricamento i dati del mondo! +text.connecting=[accent]Connessione in corso ... +text.connecting.data=[accent]Caricamento dei dati del mondo ... +text.connectfail=[crimson] Impossibile connettersi al server: [orange] {0} +text.server.port=Porta: +text.server.addressinuse=Indirizzo già in uso! +text.server.invalidport=Numero di porta non valido! +text.server.error=[crimson]Errore nell'hosting del server: [orange] {0} +text.save.new=Nuovo Salvataggio +text.save.overwrite=Sei sicuro di voler sovrascrivere questo salvataggio? +text.overwrite=Sostituisci +text.save.none=Nessun salvataggio trovato! +text.saveload=[Accent]Salvataggio ... +text.savefail=Salvataggio del gioco non riuscito! +text.save.delete.confirm=Sei sicuro di voler eliminare questo salvataggio? +text.save.delete=Elimina +text.save.export=Esporta Salva +text.save.import.invalid=[orange]Questo salvataggio non è valido! +text.save.import.fail=[crimson]Impossibile importare salvataggio: [orange]{0} +text.save.export.fail=[crimson]Impossibile esportare il salvataggio: [orange]{0} +text.save.import=Importa Salvataggio +text.save.newslot=Salva nome: +text.save.rename=Rinomina +text.save.rename.text=Nuovo nome: +text.selectslot=Seleziona un salvataggio. +text.slot=[accent]Slot {0} +text.save.corrupted=[orang]File di salvataggio danneggiato o non valido! +text.empty= +text.on=Acceso +text.off=Spento +text.save.autosave=Salvataggio automatico: {0} +text.save.map=mappa +text.save.wave=Ondata: +text.save.difficulty=Difficolta: {0} +text.save.date=Ultimo salvataggio: {0} +text.confirm=Conferma +text.delete=Elimina +text.ok=OK +text.open=Apri +text.cancel=Annulla +text.openlink=Apri Link +text.copylink=Copia link +text.back=Indietro +text.quit.confirm=Sei sicuro di voler uscire? +text.changelog.title=Registro modifiche +text.changelog.loading=Ottenere il registro delle modifiche ... +text.changelog.error.android=[orange]Nota che il log delle modifiche non funziona su Android 4.4 e versioni precedenti! Ciò è dovuto a un bug interno di Android. +text.changelog.error=[scarlet]Errore durante il recupero del changelog! Controlla la tua connessione Internet. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.loading=[accent]Caricamento in corso ... +text.wave=[orange]Onda {0} +text.wave.waiting=Onda in {0} +text.waiting=In attesa... +text.enemies={0} Nemici +text.enemies.single={0} Nemico +text.loadimage=Carica immagine +text.saveimage=Salva Immagine +text.editor.badsize=[orange]Dimensioni dell'immagine non valide![]\n Dimensioni della mappa valide: {0} +text.editor.errorimageload=Errore durante il caricamento del file immagine:\n [orange]{0} +text.editor.errorimagesave=Errore durante il salvataggio del file immagine:\n [orange]{0} +text.editor.generate=Genera +text.editor.resize=Zomma o \nRiduci +text.editor.loadmap=Carica\nmappa +text.editor.savemap=Salva\nla mappa +text.editor.loadimage=Carica\nimmagine +text.editor.saveimage=Salva\nImmagine +text.editor.unsaved=[scarlet]Hai modifiche non salvate![]\nSei sicuro di voler uscire? +text.editor.resizemap=Ridimensiona la mappa +text.editor.mapname=Nome Mappa: +text.editor.overwrite=[Accent]Attenzione!\nQuesto sovrascrive una mappa esistente. +text.editor.selectmap=Seleziona una mappa da caricare: +text.width=Larghezza: +text.height=Altezza: +text.menu=Menu +text.play=Gioca +text.load=Carica +text.save=Salva +text.language.restart=Riavvia il gioco affinché il cambiamento della lingua abbia effetto. +text.settings.language=Lingua +text.settings=Impostazioni +text.tutorial=Lezioni +text.editor=Editor +text.mapeditor=Editor delle mappe +text.donate=Dona +text.settings.reset=Resetta Alle Impostazioni Predefinite +text.settings.controls=Controlli +text.settings.game=Gioco +text.settings.sound=Suono +text.settings.graphics=Grafica +text.upgrades=Miglioramenti +text.purchased=[LIME]Creato! +text.weapons=Armi +text.paused=In pausa +text.info.title=[Accent]Informazioni +text.error.title=[crimson]Si è verificato un errore +text.error.crashtitle=Si è verificato un errore +text.blocks.blockinfo=Informazioni sul blocco +text.blocks.powercapacity=Capacità energetica +text.blocks.powershot=Danno/Colpo +text.blocks.size=Grandezza +text.blocks.liquidcapacity=Capacità del liquido +text.blocks.maxitemssecond=Oggetti massimi/secondo +text.blocks.powerrange=Raggio Energia +text.blocks.itemcapacity=Capacità oggetto +text.blocks.inputliquid=Ingresso del liquido +text.blocks.inputitem=Ingresso Oggetto +text.blocks.explosive=Altamente esplosivo! +text.blocks.health=Salute +text.blocks.inaccuracy=inesattezza +text.blocks.shots=Colpi +text.blocks.inputcapacity=Capacità di ingresso +text.blocks.outputcapacity=Capacità di uscita +setting.difficulty.easy=facile +setting.difficulty.normal=medio +setting.difficulty.hard=difficile +setting.difficulty.insane=Folle +setting.difficulty.purge=Epurazione +setting.difficulty.name=Difficoltà: +setting.screenshake.name=Screen Shake +setting.indicators.name=Indicatori nemici +setting.effects.name=Visualizza effetti +setting.sensitivity.name=Sensibilità del controllore. +setting.saveinterval.name=Intervallo di salvataggio automatico +setting.seconds={0} Secondi +setting.fullscreen.name=Schermo Intero +setting.multithread.name=multithreading +setting.fps.name=Mostra FPS +setting.vsync.name=Sincronizzazione Verticale +setting.lasers.name=Mostra Energia Dei Laser +setting.healthbars.name=Mostra barra della salute delle entità +setting.musicvol.name=Volume Musica +setting.mutemusic.name=Musica muta +setting.sfxvol.name=Volume SFX +setting.mutesound.name=Suono muto +map.maze.name=labirinto +map.fortress.name=fortezza +map.sinkhole.name=dolina +map.caves.name=grotte +map.volcano.name=vulcano +map.caldera.name=caldera +map.scorch.name=bruciatura +map.desert.name=Deserto +map.island.name=Isola +map.grassland.name=Prateria +map.tundra.name=Tundra +map.spiral.name=spirale +map.tutorial.name=Tutorial +text.keybind.title=Configurazione Tasti +keybind.move_x.name=move_x +keybind.move_y.name=move_y +keybind.select.name=seleziona +keybind.break.name=rompere +keybind.shoot.name=sparare +keybind.zoom_hold.name=zoom_hold +keybind.zoom.name=zoom +keybind.block_info.name=Informazioni blocco +keybind.menu.name=menu +keybind.pause.name=pausa +keybind.dash.name=corsa +keybind.chat.name=Chat +keybind.player_list.name=lista_giocatori +keybind.console.name=console +keybind.rotate_alt.name=rotate_alt +keybind.rotate.name=Ruotare +mode.text.help.title=Descrizione delle modalità +mode.waves.name=onde +mode.waves.description=modalità normale. risorse limitate e onde in entrata automatiche. +mode.sandbox.name=Sandbox +mode.sandbox.description=risorse infinite e nessun timer per le onde. +mode.freebuild.name=freebuild +mode.freebuild.description=risorse limitate e nessun timer per le onde. +item.stone.name=pietra +item.coal.name=carbone +item.titanium.name=titanio +item.sand.name=sabbia +liquid.water.name=acqua +liquid.lava.name=lava +liquid.oil.name=petrolio +block.door.name=porta +block.door-large.name=grande porta +block.conduit.name=Condotto +block.pulseconduit.name=condotto di impulso +block.liquidrouter.name=router liquido +block.conveyor.name=trasportatore +block.router.name=router +block.junction.name=giunzione +block.liquidjunction.name=giunzione liquida +block.sorter.name=sorter +block.smelter.name=fonderia +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.name=Thorium +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index b0b5a47d15..20cc051619 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -1,593 +1,502 @@ -text.about = 만든이 : [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n이 게임은 [orange]GDL[] Metal Monstrosity Jam 을 사용했습니다.\n\n크레딧\n- [YELLOW]bfxr[] 가 SFX 를 만듬\n- [GREEN]Roccow[] 가 음악을 만듬\n\n특별히 감사한 분들\n- [coral]MitchellFJN[]: 테스트하고 피드백을 주신 분\n- [sky]Luxray5474[]: wiki 를 만들고 코드에 기여하신 분\n- [lime]Epowerj[]: 코드를 만들고 아이콘을 제작하신 분\n- itch.io 그리고 Google Play 에서의 모든 베타 테스터 분들\n -text.credits = 크레딧 -text.discord = Mindustry 디스코드에 참여하세요! -text.changes = [SCARLET]주의!\n[]몇몇 중요한 게임 메커니즘이 변경되었습니다.\n\n- [accent]텔레포터[]는 이제 전력을 사용합니다.\n- [accent]제련소[]와 [accent]도가니[] 는 이제 최대 자원저장 공간을 가집니다.\n- [accent]도가니[] 는 이제 석탄 연료를 필요로 합니다. -text.link.discord.description = 공식 Mindustry 디스코드 채팅방 -text.link.github.description = 게임 소스코드 -text.link.dev-builds.description = 개발중인 빌드 (불안정) -text.link.trello.description = 공식 trello 보드에서 현재 계획중인 기능을 찾을 수 있습니다. -text.link.itch.io.description = itch.io 사이트에서 PC 버전 다운로드 또는 웹 버전을 플레이 할 수 있습니다. -text.link.google-play.description = Google Play 스토어 목록 -text.link.wiki.description = 공식 Mindustry 위키 -text.linkfail = 링크를 열지 못했습니다!\nURL이 클립보드에 복사되었습니다. -text.editor.web = 웹버전은 맵 편집기를 지원하지 않습니다!\n게임을 다운로드 한 후에 사용하세요. -text.web.unsupported = 이 버전의 게임은 멀티플레이를 지원하지 않습니다!\n멀티플레이를 브라우저에서 하고 싶다면 이 itch.io 페이지에서 \"Multiplayer web version\" 버튼을 눌러서 플레이 해 주세요. -text.multiplayer.web = 이 버전의 게임은 멀티플레이를 지원하지 않습니다!\n멀티플레이를 브라우저에서 하고 싶다면 이 itch.io 페이지에서 \"Multiplayer web version\" 버튼을 눌러서 플레이 해 주세요. -text.gameover = 코어가 파괴되었습니다. -text.highscore = [YELLOW]최고 점수 달성! -text.lasted = 이번 맵에서 달성한 마지막 웨이브 : -text.level.highscore = 최고 점수: [accent]{0} -text.level.delete.title = 맵 삭제 확인 -text.map.delete = 정말로 이 \"[orange]{0}\" 맵을 삭제하시겠습니까? -text.level.select = 맵 선택 -text.level.mode = 게임 모드: -text.savegame = 저장하기 -text.loadgame = 불러오기 -text.joingame = 서버참가 -text.addplayers = 플레이어 추가/제거 -text.newgame = 새 게임 -text.quit = 나가기 -text.maps = 맵 -text.about.button = 소개 -text.name = 이름: -text.unlocked = 새 블록 잠금 해제됨! -text.unlocked.plural = 새 블록들 잠금 해제됨! -text.public = 공개 -text.players = {0}명 온라인 -text.server.player.host = {0} 이 호스트함. -text.players.single = {0}명 온라인. -text.server.mismatch = 패킷오류 : 현재 게임 버전과 서버 버전이 일치하지 않습니다.\n현재 게임 버전이 최신버전인지 확인 해 주세요! -text.server.closing = [accent]서버 닫는중... -text.server.kicked.kick = 당신은 서버에서 강제 퇴장 되었습니다. -text.server.kicked.fastShoot = 너님은 총을 너무 빨리 쏴서 강퇴당했다. -text.server.kicked.invalidPassword = 잘못된 비밀번호 입니다! -text.server.kicked.clientOutdated = 현재 플레이중인 게임 버전이 낮습니다!\n게임을 업데이트 해 주세요. -text.server.kicked.serverOutdated = 이 서버는 현재 클라이언트보다 낮은 버전의 서버입니다!\n서버장에게 업데이트를 요청하세요! -text.server.kicked.banned = 당신은 이 서버에서 차단되었습니다. -text.server.kicked.recentKick = 최근에 강제 퇴장되었습니다.\n잠시 후에 다시 입장 해 주세요. -text.server.kicked.nameInUse = 이미 서버 안에 같은 닉네임을 사용하는 유저가 있습니다! -text.server.kicked.idInUse = 당신은 이미 서버에 접속하고 있습니다!\n두 계정을 한 서버에 접속하는 것은 허용되지 않습니다. -text.server.connected = {0} 님이 서버에 입장했습니다. -text.server.disconnected = {0} 님이 서버에서 나갔습니다. -text.nohost = 커스텀 맵은 서버호스팅이 불가능합니다! -text.host.info = [accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 과 [scarlet]6568[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고 : LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. -text.join.info = 여기서 [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원됩니다.\n\n[LIGHT_GRAY]참고 : 여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속할려면 서버장에게 IP를 요청해야 합니다. -text.hostserver = 서버 열기 -text.host = 호스트 -text.hosting = [accent]서버여는중... -text.hosts.refresh = 새로고침 -text.hosts.discovering = LAN 게임 찾기 -text.server.refreshing = 서버 새로고침 -text.hosts.none = [lightgray]LAN 게임이 없습니다! -text.host.invalid = [scarlet]호스트에 연결할 수 없습니다! -text.server.friendlyfire = 팀킬 허용 -text.trace = 플레이어 추적 -text.trace.playername = 플레이어 이름 : [accent]{0} -text.trace.ip = IP : [accent]{0} -text.trace.id = 고유 ID : [accent]{0} -text.trace.android = Android 클라이언트 : [accent]{0} -text.trace.modclient = 수정된 클라이언트 : [accent]{0} -text.trace.totalblocksbroken = 총 파괴한 블록 수 : [accent] -text.trace.structureblocksbroken = 총 구조 블럭 파괴수 : [accent] -text.trace.lastblockbroken = 마지막으로 파괴한 블록 : [accent]{0} -text.trace.totalblocksplaced = 총 설치한 블록 수 : [accent]{0} -text.trace.lastblockplaced = 마지막으로 설치한 블록 : [accent] -text.invalidid = 잘못된 클라이언트 ID 입니다! 공식 Mindustry 으로 버그 보고서를 제출 해 주세요. -text.server.bans = 차단된 유저들 -text.server.bans.none = 차단된 플레이어가 없습니다. -text.server.admins = 관리자들 -text.server.admins.none = 관리자가 없습니다! -text.server.add = 서버 추가 -text.server.delete = 이 서버를 삭제 하시겠습니까? -text.server.hostname = 호스트: {0} -text.server.edit = 서버 수정 -text.server.outdated = [crimson]서버 버전이 낮습니다![] -text.server.outdated.client = [Crimson]클라이언트 버전이 낮습니다![] -text.server.version = [lightgray] 버전 : {0} -text.server.custombuild = [노란색]수정된 빌드 -text.confirmban = 이 플레이어를 차단하시겠습니까? -text.confirmunban = 이 플레이어를 차단 해제 하시겠습니까? -text.confirmadmin = 이 플레이어를 관리자로 설정 하시겠습니까? -text.confirmunadmin = 이 플레이어의 관리자 상태를 해제하시겠습니까? -text.joingame.byip = IP로 참가하기... -text.joingame.title = 게임 참가 -text.joingame.ip = IP: -text.disconnect = 서버와 연결이 해제되었습니다. -text.disconnect.data = 맵 데이터를 불러오지 못했습니다! -text.connecting = [accent]연결중... -text.connecting.data = [accent]월드 데이터 로딩중... -text.connectfail = [crimson]{0}[orange] 서버에 연결하지 못했습니다.[] -text.server.port = 포트: -text.server.addressinuse = 이 주소는 이미 사용중입니다! -text.server.invalidport = 포트 번호가 잘못되었습니다. -text.server.error = [crimson]{0}[orange]서버를 호스팅 하는데 오류가 발생했습니다.[] -text.tutorial.back = < 이전 -text.tutorial.next = 다음 > -text.save.new = 새로 저장 -text.save.overwrite = 이 저장 슬롯을 덮어씌우겠습니까? -text.overwrite = 덮어쓰기 -text.save.none = 저장 파일을 찾지 못했습니다! -text.saveload = [accent]저장중... -text.savefail = 게임을 저장하지 못했습니다! -text.save.delete.confirm = 이 저장파일을 삭제 하시겠습니까? -text.save.delete = 삭제 -text.save.export = 저장파일 내보내기 -text.save.import.invalid = [orange] 저장파일이 유효한 파일이 아닙니다!\n\n다른 디바이스에 있는 커스텀 맵을 가져오는건 작동하지 않습니다. -text.save.import.fail = [crimson]저장파일을 불러오지 못함: [orange]{0} -text.save.export.fail = [crimson]저장파일을 내보내지 못함: [orange]{0} -text.save.import = 저장파일 불러오기 -text.save.newslot = 저장 파일이름 : -text.save.rename = 이름 변경 -text.save.rename.text = 새 이름 : -text.selectslot = 저장슬롯을 선택하십시오. -text.slot = [accent]{0}번째 슬롯 -text.save.corrupted = [orange]저장파일이 손상되었습니다! -text.empty = <비어있음> -text.on = 켜기 -text.off = 끄기 -text.save.autosave = 자동저장: {0} -text.save.map = 맵: {0} -text.save.wave = {0} 단계 -text.save.difficulty = 난이도 : {0} -text.save.date = 마지막 저장 날짜 : {0} -text.confirm = 확인 -text.delete = 삭제 -text.ok = 확인 -text.open = 열기 -text.cancel = 취소 -text.openlink = 링크 열기 -text.copylink = 링크 복사 -text.back = 뒤로 -text.quit.confirm = 종료 하시겠습니까? -text.changelog.title = 변경사항 -text.changelog.loading = 업데이트 내역 가져오는중.. -text.changelog.error.android = [orange]업데이트 내역은 가끔 Android 4.4 이하에서 작동하지 않습니다.\n이것은 Android 내부 버그입니다. -text.changelog.error.ios = [orange]현재 업데이트 내역은 iOS 에서 지원하지 않습니다. -text.changelog.error = [searlet]업데이트 내역을 가져오는데 오류가 발생했습니다!\n인터넷 연결을 확인 해 주세요. -text.changelog.current = [yellow][[현재 버전] -text.changelog.latest = [orange][[최신 버전] -text.loading = [accent]로딩중 ... -text.wave = [orange] {0} 단계 -text.wave.waiting = 다음 단계까지 {0} 초 남음 -text.waiting = 대기 중... -text.enemies = 남은 잡몹 수 : {0} -text.enemies.single = {0} 마리 남음 -text.loadimage = 사진 불러오기 -text.saveimage = 사진 저장 -text.unknown = 알 수 없음 -text.custom = 관습 -text.builtin = 내장 -text.map.delete.confirm = 이 맵을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다! -text.editor.openin = 편집기에서 열기 -text.editor.oregen = 광물 생성 -text.editor.oregen.info = 광물 생성: -text.editor.mapinfo = 맵 정보 -text.editor.author = 작성자: -text.editor.description = 설명: -text.editor.name = 이름: -text.editor.teams = 팀 -text.editor.badsize = [orange]사진 크기가 잘못되었습니다![]\n유효한 맵 크기 : {0} -text.editor.errorimageload = 파일을 불러오는 중 오류 발생 : [orange]{0} -text.editor.errorimagesave = 파일 저장 중 오류 발생 : [orange] {0} -text.editor.generate = 생성 -text.editor.resize = 크기 조정 -text.editor.loadmap = 맵 불러오기 -text.editor.savemap = 맵 저장 -text.editor.saved = 저장됨! -text.editor.save.noname = 지도에 이름이 없습니다! '지도 정보'메뉴에서 하나를 설정하십시오. -text.editor.save.overwrite = 귀하의지도는 내장 된지도를 덮어 씁니다! '지도 정보'메뉴에서 다른 이름을 선택하십시오. -text.editor.import = 가져오기 -text.editor.importmap = 지도 가져 오기 -text.editor.importmap.description = 이미 존재하는지도 가져 오기 -text.editor.importfile = 파일 가져오기 -text.editor.importfile.description = 외부 맵 파일 가져 오기 -text.editor.importimage = 지형 이미지 가져 오기 -text.editor.importimage.description = 외부지도 이미지 파일 가져 오기 -text.editor.export = 내보내기 -text.editor.exportfile = 파일 내보내기 -text.editor.exportfile.description = 지도 파일 내보내기 -text.editor.exportimage = 지형 이미지 내보내기 -text.editor.exportimage.description = 지도 이미지 파일 내보내기 -text.editor.loadimage = 지형 가져 오기 -text.editor.saveimage = 지형 내보내기 -text.editor.unsaved = [scarlet]변경사항을 저장하지 않았습니다![]\n종료하시겠습니까? -text.editor.brushsize = 브러쉬 크기 : -text.editor.noplayerspawn = 이맵에는 플레이어의 스폰 지점이 없습니다! -text.editor.manyplayerspawns = 맵에는 플레이어 스폰 지점이 둘 이상 있을 수 없습니다! -text.editor.manyenemyspawns = 잡몹 스폰지점을 개 이상으로 지정할 수 없습니다! -text.editor.resizemap = 맵 크기 조정 -text.editor.resizebig = [scarlet]경고!\n[]맵 크기가 256이상일경우 랙이 걸리거나 게임이 불안정할 수 있습니다. -text.editor.mapname = 맵 이름 : -text.editor.overwrite = [accent]경고!\n이 작업은 기존 맵을 덮어 쓰게 됩니다! -text.editor.selectmap = 불러올 맵 선택 : -text.width = 넓이 : -text.height = 높이: -text.randomize = 무작위 -text.apply = 적용 -text.update = 업데이트 -text.menu = 메뉴 -text.play = 플레이 -text.load = 불러오기 -text.save = 저장 -text.language.restart = 언어 설정을 적용하려면 게임을 다시 시작하십시오. -text.settings.language = 언어 -text.settings = 설정 -text.tutorial = 자습서 -text.editor = 에디터 -text.mapeditor = 맵 에디터 -text.donate = 기부하기 -text.settings.reset = 기본값으로 재설정 -text.settings.rebind = rebind -text.settings.controls = 컨트롤 -text.settings.game = 게임 설정 -text.settings.sound = 소리 설정 -text.settings.graphics = 그래픽 설정 -text.upgrades = 업그레이드 -text.purchased = [LIME]제작됨! -text.weapons = 무기 -text.paused = 일시중지 -text.respawn = 남은 부활 시간 : -text.info.title = [accent]정보 -text.error.title = [crimson]예기지 않은 오류가 발생했습니다! -text.error.crashmessage = [SCARLET]예기치 못한 오류가 발생하여, 무언가 충돌을 일으켰습니다\n[]이 오류에 대한 정확한 내용을 개발자에게 전달해 주세요!\n[ORANGE]anukendev@gmail.com[] 또는 [orange]Mindustry 디스코드[orange]로 보내주세요! -text.error.crashtitle = 오류 발생! -text.mode.break = 삭제 모드 : -text.mode.place = 설치 모드 : -placemode.hold.name = 라인 -placemode.areadelete.name = 구역 삭제 -placemode.touchdelete.name = 클릭하여 삭제 -placemode.holddelete.name = 길게 눌러 삭제 -placemode.none.name = 없음 -placemode.touch.name = 클릭 -placemode.cursor.name = 커서 -text.blocks.extrainfo = [accent]추가 블록 정보: -text.blocks.blockinfo = 블록 정보 -text.blocks.powercapacity = [powerinfo]전력 용량 -text.blocks.powershot = [turretinfo]전력당 발사 수 -text.blocks.powersecond = [powerinfo]초당 전력량 -text.blocks.powerdraindamage = [powerinfo]전력 소모량당 데미지 량 -text.blocks.shieldradius = [powerinfo]보호막 반경 -text.blocks.itemspeedsecond = [iteminfo]초당 아이템 속도 -text.blocks.range = [turretinfo]범위 -text.blocks.size = [gray]크기 -text.blocks.powerliquid = [powerinfo]전력당 액체량 -text.blocks.maxliquidsecond = [liquidinfo]초당 최대 액체량 -text.blocks.liquidcapacity = [liquidinfo]액체 저장량 -text.blocks.liquidsecond = [liquidinfo]초당 액체량 -text.blocks.damageshot = [turretinfo]1발당 데미지 -text.blocks.ammocapacity = [turretinfo]탄약 적재량 -text.blocks.ammo = [turretinfo]탄약 -text.blocks.ammoitem = [turretinfo]탄약당 아이템 -text.blocks.maxitemssecond = [iteminfo]초당 최대 아이템 수 -text.blocks.lasertilerange = [powerinfo]레이저 타일 범위 -text.blocks.capacity = [iteminfo]용량 -text.blocks.itemcapacity = [iteminfo]아이템 용량 -text.blocks.maxpowergenerationsecond = [powerinfo]초당 최대 발전량 -text.blocks.powergenerationsecond = [powerinfo]초당 발전량 -text.blocks.generationsecondsitem = [powerinfo]초당 생성 아이템 수 -text.blocks.input = [liquidinfo]입력 -text.blocks.inputliquid = [liquidinfo]입력 액체 -text.blocks.inputitem = [liquidinfo]입력 아이템 -text.blocks.output = [liquidinfo]출력 -text.blocks.secondsitem = [liquidinfo]초당 아이템 수 -text.blocks.maxpowertransfersecond = [powerinfo]초당 최대 전력 이송량 -text.blocks.explosive = [orange]이 건물이 파괴되면 큰 폭발이 일어납니다! -text.blocks.repairssecond = [turretinfo]초당 수리력 -text.blocks.health = [healthstats]체력 -text.blocks.inaccuracy = [turretinfo]명중하지 않을 확률 -text.blocks.shots = [turretinfo]발사수 -text.blocks.shotssecond = [turretinfo]초당 발사수 -text.blocks.fuel = [craftinfo]연료 -text.blocks.fuelduration = [craftinfo]연료 지속 시간 -text.blocks.maxoutputsecond = [craftinfo]초당 최대 출력 수 -text.blocks.inputcapacity = [craftinfo]초당 입력 수 -text.blocks.outputcapacity = [craftinfo]초당 출력 수 -text.blocks.poweritem = [powerinfo]전력당 아이템 수 -text.placemode = 설치 모드 -text.breakmode = 삭제 모드 -text.health = 체력 -setting.difficulty.easy = 쉬움 -setting.difficulty.normal = 보통 -setting.difficulty.hard = 어려움 -setting.difficulty.insane = 미쳤음 -setting.difficulty.purge = 청소기 -setting.difficulty.name = 난이도: -setting.screenshake.name = 화면 흔들림 -setting.smoothcam.name = 부드러운 카메라 이동 -setting.indicators.name = 적 위치 표시 화살표 -setting.effects.name = 화면 효과 -setting.sensitivity.name = 컨트롤러 감도 -setting.saveinterval.name = 자동 저장 간격 -setting.seconds = 초 -setting.fullscreen.name = 전체 화면 -setting.multithread.name = 멀티 스레드 활성화 -setting.fps.name = 초당 프레임 표시 -setting.vsync.name = 수직동기화 -setting.lasers.name = 파워 레이저 표시 -setting.previewopacity.name = 블럭 배치 미리보기 표시 -setting.healthbars.name = 체력 막대바 표시 -setting.pixelate.name = 화면 픽셀화 -setting.musicvol.name = 음악 볼륨 -setting.mutemusic.name = 음악 끄기 -setting.sfxvol.name = 효과음 볼륨 -setting.mutesound.name = 효과음 끄기 -map.maze.name = 미로 -map.fortress.name = 요새 -map.sinkhole.name = 싱크홀 -map.caves.name = 동굴 -map.volcano.name = 화산 -map.caldera.name = 칼데라 -map.scorch.name = 타버린 세계 -map.desert.name = 사막 -map.island.name = 섬 -map.grassland.name = 초원 -map.tundra.name = 툰드라 -map.spiral.name = 나선 -map.tutorial.name = 자습서 -tutorial.intro.text = [yellow] 자습서에 오신 것을 환영합니다.[] 시작하려면 '다음'을 누르세요. -tutorial.moveDesktop.text = 이동하려면 [orange] [[WASD] [] 키를 사용하세요. 또한, [orange]Shift[]를 누르고 있으면 빠르게 이동할 수 있습니다. [orange]CTRL[]을 누른 상태에서 [orange] 마우스 스크롤 휠 []을 사용하여 확대 또는 축소 할 수 있습니다 -tutorial.shoot.text = 마우스를 사용하여 조준하고 [orange]왼쪽 마우스 버튼[]을 눌러 쏘세요. 저기 노란색 [yellow]타겟[]앞에서 연습해보세요. -tutorial.moveAndroid.text = 화면을 이동하기 위해서 한손가락으로 드래그 해 보세요. 확대 및 축소는 두손가락으로 하시면 됩니다. -tutorial.placeSelect.text = 오른쪽 하단에 있는 블럭 메뉴에서 [yellow]컨베이어[]를 선택하세요. -tutorial.placeConveyorDesktop.text = [orange][[마우스 스크롤 휠][]을 사용하여 컨베이어를[orange]앞 방향[]으로 돌린다음 [yellow]표시된 위치[]에 [orange][[왼쪽 마우스 버튼][]을 이용해 컨베이어를 설치 합니다. -tutorial.placeConveyorAndroid.text = 컨베이어를 회전 시키기 위해[orange][[회전 버튼][]를 누르고 [orange]앞방향[]을 보게 한후, 한손가락으로 [yellow]표시된 위치[]에 [orange][[확인][] 버튼으로 설치하세요. -tutorial.placeConveyorAndroidInfo.text = 아니면 왼쪽 하단에 [orange][[설치 모드][]를 눌러 클릭모드로 전환하고 클릭만으로 블럭을 배치 할수 있습니다.\n방향을 바꾸려면 왼쪽하단 5번째 칸에 있는 화살표로 바꾸시면 됩니다.\n[yellow]다음[]을 눌러 한번 해 보세요. -tutorial.placeDrill.text = 이제, 표시된 위치에 [yellow]돌 드릴[]을 선택하여 배치하세요. -tutorial.blockInfo.text = 블록에 대해 더 자세히 알고 싶다면, 오른쪽 상단에있는 [orange]물음표[]를 눌러 설명을 읽으세요. -tutorial.deselectDesktop.text = [orange][[마우스 오른쪽 버튼][]을 사용하여 블록을 선택 해제할 수 있습니다. -tutorial.deselectAndroid.text = [orange]X[] 버튼을 눌러 블록을 선택 해제할 수 있습니다. -tutorial.drillPlaced.text = 드릴은 이제 [yellow] 돌[]을 생산할 것이고, 컨베이어로 내보낸 다음 [yellow]코어[]로 옮길 것입니다. -tutorial.drillInfo.text = 각 광석은 그에 맞는 드릴이 필요합니다. 돌은 돌 드릴이 필요하고, 철은 철 드릴이 필요합니다. -tutorial.drillPlaced2.text = 아이템을 코어로 이동하면 왼쪽 상단의 [orange]아이템 인벤토리[]에 표시됩니다.\n인벤토리의 아이템은 블록을 배치할때 사용됩니다. -tutorial.moreDrills.text = 드릴과 컨베이어는 많이 연결할 수 있습니다. 이것처럼요. -tutorial.deleteBlock.text = 블록을 삭제하고 싶으면 [orange]마우스 오른쪽 버튼[]을 클릭하여 블록을 삭제할 수 있습니다.\n이 컨베이어를 삭제 해 보세요. -tutorial.deleteBlockAndroid.text = 왼쪽 하단에 있는 [orange]블록 삭제모드[]안에 [orange]십자선[] 아이콘을 선택한 다음 블록을 눌러 삭제할 수 있습니다. 이 컨베이어를 삭제해 보세요. -tutorial.placeTurret.text = 이제[yellow] 표시된 위치 []에 [yellow]포탑[]을 선택하여 배치하세요. -tutorial.placedTurretAmmo.text = 이 포탑은 컨베이어에서 [yellow]탄약[]을 받습니다.\n포탑에 커서를 가리키면 [green]녹색 막대[]를 통해 얼마나 많은 탄약이 포탑 안에있는지 확인 할수 있습니다. -tutorial.turretExplanation.text = 포탑은 충분한 탄약을 보유하고있는 한, 범위 내의 가장 가까운 적을 향해 자동으로 공격합니다. -tutorial.waves.text = [yellow]60[]초 마다, 웨이브가 시작되고[coral]적[]들이 특정 위치에 스폰되어 코어를 파괴하기위해 올 것 입니다. -tutorial.coreDestruction.text = 당신의 목표는 [yellow]코어를 최대한 오래동안 방어하는 것[]입니다. 코어가 파괴되면 [coral]게임에서 패배합니다[]. -tutorial.pausingDesktop.text = 휴식을 취해야 하는 경우, 왼쪽 상단에 있는 [orange]일시정지 버튼[] 을 누르거나 [orange]스페이스바[] 를 눌러 게임을 일시정지 시킬 수 있습니다.\n일시정지된 상태에서 블록을 선택하고 배치할 수는 있지만, 움직이거나 공격할 수는 없습니다. -tutorial.pausingAndroid.text = 휴식을 취해야 하는 경우, 왼쪽 상단에 있는 [orange]일시정지 버튼[] 을 눌러 게임을 일시정지 시킬 수 있습니다.\n일시정지된 상태에서 블록을 선택하고 배치할 수는 있지만, 움직이거나 공격할 수는 없습니다. -tutorial.purchaseWeapons.text = 왼쪽 하단에 있는 업그레이드 메뉴를 열어 새로운 [yellow]무기[]를 구입할 수 있습니다. -tutorial.switchWeapons.text = 왼쪽 하단의 아이콘을 클릭하거나 숫자 [orange][[1-9][] 버튼을 사용하여 무기를 바꿀 수 있습니다. -tutorial.spawnWave.text = 웨이브가 시작되었습니다. 적들을 파괴하세요! -tutorial.pumpDesc.text = 이후 웨이브에선 발전기 또는 추출기용 액체를 사용하기 위해 [yellow]펌프[] 를 사용해야 할 수도 있습니다 -tutorial.pumpPlace.text = 펌프는 드릴과 유사하게 작동하지만, 아이템 대신 액체를 생산합니다. [yellow]지정된 위치[]에 펌프를 놓으세요. -tutorial.conduitUse.text = 이제 [orange]파이프[] 를 펌프에서 멀리 떨어트려 두세요 -tutorial.conduitUse2.text = 하나 더... -tutorial.conduitUse3.text = 하나 더... -tutorial.generator.text = 이제 파이프 끝 부분에 [orange]석유 발전기[] 블록을 놓으세요. -tutorial.generatorExplain.text = 이제 이 발전기는 석유에서 [yellow]전력[]을 생성합니다. -tutorial.lasers.text = 전력은 [yellow]파워 레이저[]를 통해 전송됩니다. 회전한 후 이곳에 배치하세요. -tutorial.laserExplain.text = 발전기가 이제 레이저 블록으로 전력을 보냅니다.\n[yellow]불투명[] 광선은 현재 전력을 전송 중임을 의미하고 [yellow]투명[] 광선은 전송하지 않음을 의미합니다. -tutorial.laserMore.text = 블록 위로 마우스를 올리고 상단의 [yellow]노란 막대[]를 확인하여 블록의 전력을 볼 수 있습니다 -tutorial.healingTurret.text = 이 레이저는 [lime]수리포탑[] 에 전력을 공급하는데 사용합니다. 여기에 하나 놓으세요 -tutorial.healingTurretExplain.text = 전력이 있는 한 이 포탑은 [lime]주변 블록을 수리[] 합니다.\n시간이 있을 때 가능한 빨리 기지에 하나가 있는지 확인하세요! -tutorial.smeltery.text = 많은 블록들은[orange]강철[]을 필요로 합니다.\n[orange]제련소[]를 선택해 여기에 놓으세요. -tutorial.smelterySetup.text = 이 제련소는 석탄을 연료로 사용하며 철을 넣으면 [orange]강철[] 을 생산할 것입니다. -tutorial.tunnelExplain.text = 또한 아이템이 [orange]터널 블록[]을 통해 지나가고 다른 쪽에서 돌 블록을 통과하여 나옵니다.\n터널은 최대 2블록까지만 통과할 수 있습니 -tutorial.end.text = 이것으로 자습서를 마칩니다! 행운을 빕니다! -text.keybind.title = 키 지정 -keybind.move_x.name = x축 이동 -keybind.move_y.name = y축 이동 -keybind.select.name = 선택 -keybind.break.name = 블럭 삭제 -keybind.shoot.name = 발사 -keybind.zoom_hold.name = 확대 할때 누를 버튼 -keybind.zoom.name = 확대 -keybind.block_info.name = 블록 정보 -keybind.menu.name = 메뉴 -keybind.pause.name = 일시정지 -keybind.dash.name = 달리기 -keybind.chat.name = 대화창 -keybind.player_list.name = player_list -keybind.console.name = 콘솔 -keybind.rotate_alt.name = 반대로 돌기 -keybind.rotate.name = 회전 -keybind.weapon_1.name = 무기 단축키_1 -keybind.weapon_2.name = 무기 단축키_2 -keybind.weapon_3.name = 무기 단축키_3 -keybind.weapon_4.name = 무기 단축키_4 -keybind.weapon_5.name = 무기 단축키_5 -keybind.weapon_6.name = 무기 단축키_6 -mode.text.help.title = 모드 설명 -mode.waves.name = 단계 -mode.waves.description = 이것은 일반 모드입니다. 제한된 자원과 자동으로 웨이브가 시작됩니다. -mode.sandbox.name = 샌드박스 -mode.sandbox.description = 무한한 자원과 웨이브를 시작하는 타이머가 없습니다. -mode.freebuild.name = 자유 건설 -mode.freebuild.description = 제한된 자원을 가지고 있으며, 웨이브를 시작하기 위한 타이머가 없습니다. -upgrade.standard-mech.name = 기본 -upgrade.standard-mech.description = 그냥 기본 총. -upgrade.standard-ship.name = 기본 배 -upgrade.standard-ship.description = 그냥 기본 배 -upgrade.blaster.name = 블래스터 -upgrade.blaster.description = 그냥 느리고 약한 총알. -upgrade.triblaster.name = 3단 블래스터 -upgrade.triblaster.description = 3발을 동시에 쏘는 총. -upgrade.clustergun.name = 유탄발사기 -upgrade.clustergun.description = 적에 맞으면 폭발하거나, 일정시간 후 터집니다. -upgrade.beam.name = 레이저 캐논 -upgrade.beam.description = 적을 통과하는 장거리 레이저 빔을 쏩니다 -upgrade.vulcan.name = 벌칸 -upgrade.vulcan.description = 빠른 속도로 총을 쏩니다 -upgrade.shockgun.name = 샷건 -upgrade.shockgun.description = 충전된 총알을 산탄처럼 쏘는 총 -item.stone.name = 돌 -item.iron.name = 철 -item.coal.name = 석탄 -item.steel.name = 강철 -item.titanium.name = 티타늄 -item.dirium.name = 합금 -item.thorium.name = 토륨 -item.sand.name = 모래 -liquid.water.name = 물 -liquid.plasma.name = 플라즈마 -liquid.lava.name = 용암 -liquid.oil.name = 석유 -block.weaponfactory.name = 무기 공장 -block.weaponfactory.fulldescription = 플레이어용 무기를 만드는 데 사용됩니다.\n클릭하여 사용하십시오.\n코어에 있는 자원을 사용합니다. -block.air.name = 공기 -block.blockpart.name = 블록파트 -block.deepwater.name = 깊은 물 -block.water.name = 물 -block.lava.name = 용암 -block.oil.name = 석유 -block.stone.name = 돌 -block.blackstone.name = 검은 돌 -block.iron.name = 철 -block.coal.name = 석탄 -block.titanium.name = 티타늄 -block.thorium.name = 토륨 -block.dirt.name = 흙 -block.sand.name = 모래 -block.ice.name = 얼음 -block.snow.name = 눈 -block.grass.name = 잔디 -block.sandblock.name = 모래블럭 -block.snowblock.name = 얼음 블럭 -block.stoneblock.name = 돌 블럭 -block.blackstoneblock.name = 검은 돌 블럭 -block.grassblock.name = 잔디 블럭 -block.mossblock.name = 이끼블럭 -block.shrub.name = 덤불 -block.rock.name = 바위 -block.icerock.name = 얼음 덩어리 -block.blackrock.name = 검은 바위 -block.dirtblock.name = 흙 블럭 -block.stonewall.name = 돌 벽 -block.stonewall.fulldescription = 가장 안좋은 그냥 돌벽. 초반에 코어와 포탑을 보호하는데 사용 할 수 있습니다. -block.ironwall.name = 철 벽 -block.ironwall.fulldescription = 기본적인 벽 블럭. 적으로부터 보호해 줍니다. -block.steelwall.name = 강철 벽 -block.steelwall.fulldescription = 나름 좋은 벽 블럭. 적으로부터의 공격을 대부분 보호해 줍니다. -block.titaniumwall.name = 티타늄 벽 -block.titaniumwall.fulldescription = 강력한 벽 블럭. 적으로부터의 공격을 거의 보호해 줍니다 -block.duriumwall.name = 합금 벽 -block.duriumwall.fulldescription = 매우 강력한 벽 블록. 게임내에서 가장 강력한 벽 입니다. -block.compositewall.name = 복합 벽 -block.steelwall-large.name = 대형 강철 벽 -block.steelwall-large.fulldescription = 좋은 벽 블럭. 2x2 크기에 큰 벽입니다. -block.titaniumwall-large.name = 대형 티타늄 벽 -block.titaniumwall-large.fulldescription = 강력한 벽 블럭. 2x2 크기에 큰 벽입니다. -block.duriumwall-large.name = 대형 디리듐 벽 -block.duriumwall-large.fulldescription = 매우 강력한 벽 블록. 2x2 크기에 큰 벽입니다. -block.titaniumshieldwall.name = 보호막 벽 -block.titaniumshieldwall.fulldescription = 보호막이 내장 된 강력한 벽 블럭입니다.\n적의 총알을 흡수할 때 에너지를 사용하기 때문에 전력이 필요합니다.\n전력을 공급할때 무선 공급기를 사용하면 편리합니다 . -block.repairturret.name = 수리포탑 -block.repairturret.fulldescription = 범위 안에 있는 손상된 블록을 느린 속도로 수리합니다. 소량의 전력을 사용합니다. -block.megarepairturret.name = 수리포탑 II -block.megarepairturret.fulldescription = 범위 안에 있는 손상된 블록을 수리합니다. 전력을 사용합니다. -block.shieldgenerator.name = 보호막 발전기 -block.shieldgenerator.fulldescription = 고급 보호 블록. 반경 내의 모든 블록을 공격으로부터 보호합니다.\n작동 중일 때는 느린 속도로 전력을 사용하지만 공격을 받았을 시 그만큼의 전력을 소모하게 됩니다. -block.door.name = 문 -block.door.fulldescription = 블록을 탭하여 열거나 닫을 수 있습니다. -block.door-large.name = 대형 문 -block.door-large.fulldescription = 블록을 탭하여 열거나 닫을 수 있습니다. 2x2 크기 입니다. -block.conduit.name = 파이프 -block.conduit.fulldescription = 기본 액체 이송 블록. 컨베이어처럼 작동하지만 액체를 운반하는데 쓰입니다.\n펌프 또는 다른 파이프와 함께 사용하는 것이 가장 좋습니다.\n적과 플레이어가 액체를 건널때 쓰일수도 있습니다. -block.pulseconduit.name = 펄스 파이프 -block.pulseconduit.fulldescription = 파이프에 상위호환, 액체를 더 빨리 운반하고 파이프보다 더 많이 저장합니다. -block.liquidrouter.name = 액체 분배기 -block.liquidrouter.fulldescription = 분배기와 유사하게 작동합니다.\n한 방향으로 액체를 입력받아 다른 방향으로 출력합니다. 하나의 파이프에서 다른 파이프들로 액체를 분배할 때 유용합니다. -block.conveyor.name = 컨베이어 -block.conveyor.fulldescription = 기본 컨베이어.\n아이템을 앞으로 운반시켜 자동으로 포탑이나 제작기에 넣어 줍니다.\n회전이 가능하고 적과 플레이어의 다리가 될 수도 있습니다. -block.steelconveyor.name = 강철 컨베이어 -block.steelconveyor.fulldescription = 빠른 컨베이어, 표준 컨베이어보다 빠르게 아이템을 운반합니다. -block.poweredconveyor.name = 펄스 컨베이어 -block.poweredconveyor.fulldescription = 가장 빠른 컨베이어. 강철 컨베이어보다 매우 항목을 이동합니다. -block.router.name = 분배기 -block.router.fulldescription = 한 방향으로 아이템을 받아 다른 방향으로 출력합니다.\n하나의 컨베이어에서 다른 컨베이어들로 아이템을 분배할 때 유용합니다 -block.junction.name = 교차기 -block.junction.fulldescription = 두 개의 컨베이어를 교차시키는 역할을합니다.\n교차된 위치의 다른 재료를 담고있는 2개의 컨베이어가 있는 상황에서 유용합니다. -block.conveyortunnel.name = 컨베이어 터널 -block.conveyortunnel.fulldescription = 한블럭 단위로 아이템을 전송 합니다.\n이 블럭을 사용하려면 두 터널이 한블럭을 사이로 서로 반대 방향을 향하게하세요. -block.liquidjunction.name = 액체 교차기 -block.liquidjunction.fulldescription = 교차기와 유사하며 두 개 파이프를 교차시키는 역할을합니다.\n교차된 위치의 다른 액체를 담고있는 2개의 파이프가 있는 상황에서 유용합니다. -block.liquiditemjunction.name = 액체 아이템 교차기 -block.liquiditemjunction.fulldescription = 파이프와 컨베이어를 교차시키는 역할을합니다. -block.powerbooster.name = 무선 전력 공급기 -block.powerbooster.fulldescription = 반경 내에 무선으로 전력을 공급합니다. -block.powerlaser.name = 파워 레이저 -block.powerlaser.fulldescription = 반경 내에 바라보는 블록에 전력을 전송하는 레이저를 쏩니다.\n전력을 생성하지는 않고 발전기 또는 다른 레이저와 함께 사용하는 것이 가장 좋습니다. -block.powerlaserrouter.name = 레이저 분배기 -block.powerlaserrouter.fulldescription = 한 번에 세 방향으로 전력을 전송하는 레이저를 쏩니다.\n하나의 발전기에서 여러 개의 블록에 전원을 공급해야하는 경우에 유용합니다. -block.powerlasercorner.name = 코너 레이저 -block.powerlasercorner.fulldescription = 한 번에 두 방향으로 전력을 전송하는 레이저를 쏩니다.\n하나의 발전기에서 여러 개의 블록에 전원을 공급해야하는 상황에서 유용합니다 -block.teleporter.name = 텔레포터 -block.teleporter.fulldescription = 고급 아이템 전송 블록.\n텔레포터는 동일한 색깔의 다른 텔레포터에게 아이템을 전송합니다.\n같은 색의 텔레포터가 없다면 아무것도 하지 않습니다.\n동일한 색상의 여러 텔레포터가 있는 경우 임의의 하나에게 전송됩니다.\n전원을 사용하고, 눌러서 색깔을 바꿀수 있습니다. -block.sorter.name = 필터 -block.sorter.fulldescription = 유형별로 아이템을 정렬합니다.\n통과할 아이템은 블록의 색상으로 표시됩니다.\n통과된 아이템은 앞으로 출력 되고 나머지는 왼쪽과 오른쪽으로 출력됩니다. -block.splitter.name = 분리 -block.splitter.fulldescription = 들어오는 자원을 두 방향으로 분할해서 출력합니다.\n왼쪽과 오른쪽만 출력하고 라우터와 달리 내부 저장공간이 없고 즉시 출력됩니다. -block.core.name = 코어 -block.pump.name = 펌프 -block.pump.fulldescription = 물, 용암 또는 기름과 같은 액체를 퍼올립니다.\n붙어있는 파이프에게 액체를 배출합니다. -block.fluxpump.name = 플럭스 펌프 -block.fluxpump.fulldescription = 빠른 펌프. 더 많은 액체를 저장하고 액체를 더 빠르게 퍼올립니다. -block.smelter.name = 제련소 -block.smelter.fulldescription = 필수적인 제작 블록.\n1개의 철과 1개의 석탄을 연료로 넣으면 하나의 강철을 생성합니다.\n막힘을 방지하기 위해 철과 석탄을 다른 컨베이어에 넣는 것이 좋습니다. -block.crucible.name = 합금 제련소 -block.crucible.fulldescription = 고급 제작 블록.\n티타늄 1개, 강철 1개, 석탄 1개를 연료로 넣으면 하나의 합금을 출력합니다.\n막힘을 방지하기 위해 석탄, 강철 및 티타늄을 다른 컨베이어에 입력하는 것이 좋습니다. -block.coalpurifier.name = 석탄 추출기 -block.coalpurifier.fulldescription = 간단한 추출기. 다량의 물과 돌이 공급되면 석탄을 생산합니다. -block.titaniumpurifier.name = 티타늄 추출기 -block.titaniumpurifier.fulldescription = 기본 추출기 블록. 다량의 물과 철이 공급되면 티타늄을 생산합니다. -block.oilrefinery.name = 정유소 -block.oilrefinery.fulldescription = 다량의 기름을 석탄으로 정제합니다.\n석탄이 부족할 때 석탄 기반 포탑에 연료를 공급하는 데 유용합니다. -block.stoneformer.name = 돌 생산기 -block.stoneformer.fulldescription = 용암을 돌로 바꿉니다. 석탄 추출기용 돌을 대량 생산할 때 유용합니다. -block.siliconextractor.name = 실리콘 추출기 -block.pulverizer.name = 분쇄기 -block.quartzextractor.name = 석영 추출기 -block.lavasmelter.name = 용암 제련소 -block.lavasmelter.fulldescription = 용암을 사용하여 철을 강철로 전환합니다. 제련소의 대안으로 쓸수 있습니다.\n석탄이 부족한 상황에서 유용합니다. -block.stonedrill.name = 돌 드릴 -block.stonedrill.fulldescription = 필수 적인 드릴. 돌 타일 위에 놓을 때 느린속도로 채굴합니다. -block.irondrill.name = 철 드릴 -block.irondrill.fulldescription = 기본 드릴. 철 광석 타일에 놓으면 느린속도로 철을 채굴합니다. -block.coaldrill.name = 석탄 드릴 -block.coaldrill.fulldescription = 기본 드릴. 석탄 광석 타일 위에 놓으면 느린속도로 석탄을 채굴 합니다. -block.thoriumdrill.name = 토륨 드릴 -block.thoriumdrill.fulldescription = 고급 드릴. 토륨 광석 타일에 이 블럭을 놓으면, 느린 속도로 토륨을 채굴합니다. -block.titaniumdrill.name = 티타늄 드릴 -block.titaniumdrill.fulldescription = 고급 드릴. 티타늄 광석 타일 위에 놓으면 느린속도로 티타늄을 채굴합니다. -block.omnidrill.name = 옴니 드릴 -block.omnidrill.fulldescription = 빠른 속도로 모든 광석을 채굴 할 수 있습니다. -block.coalgenerator.name = 석탄 발전기 -block.coalgenerator.fulldescription = 필수적인 발전기. 석탄으로 전력을 생산합니다. 4면에 레이저로 전력을 출력합니다. -block.thermalgenerator.name = 지열 발전기 -block.thermalgenerator.fulldescription = 용암으로부터 전력을 생산합니다. 4면에 레이저로 전력을 출력합니다. -block.combustiongenerator.name = 석유 발전기 -block.combustiongenerator.fulldescription = 기름에서 전력을 생산합니다. 4면에 레이저로 전력을 출력합니다. -block.rtgenerator.name = 우라늄 발전기 -block.rtgenerator.fulldescription = 토륨에서 나오는 방사선으로 적은 량의 전력을 생산합니다.\n4면으로 전력이 출력됩니다. -block.nuclearreactor.name = 원자로 -block.nuclearreactor.fulldescription = 우라늄 발전기의 고급 버전과 궁극의 발전기.\n토륨에서 전력을 생산합니다.\n\n냉각수가 필요하며, 높은 휘발성을 가지고 있습니다.\n이 건물을 작동시키기 위해 연료로 토륨을 필요로 합니다. -block.turret.name = 포탑 -block.turret.fulldescription = 즉석에서 만들 수 있고 가장 쓰레기인 포탑.\n탄약으로 돌을 사용합니다.\n\n이중 포탑보다 약간 넓은 범위를가집니다. -block.doubleturret.name = 2단 포탑 -block.doubleturret.fulldescription = 포탑의 상위 버전입니다.\n탄약으로 돌을 사용합니다.\n\n더 많은 데미지를 주지만 범위는 낮습니다.\n총알 2발을 동시에 발사합니다. -block.machineturret.name = 게틀링 포탑 -block.machineturret.fulldescription = 표준적인 포탑.\n탄약으로 철을 사용합니다.\n\n적당한 데미지에 빠른 발사 속도를 가지고 있습니다. -block.shotgunturret.name = 스플리터 포탑 -block.shotgunturret.fulldescription = 표준적인 포탑.\n탄약으로 철을 사용합니다.\n\n한방에 7발을 발사합니다.\n범위가 낮지만 게틀링 포탑보다 높은 데미지를 가지고 있습니다. -block.flameturret.name = 화염 포탑 -block.flameturret.fulldescription = 고급 근거리 포탑.\n탄약으로 석탄을 사용합니다.\n\n범위는 낮지만 높은 데미지를 가지고 있습니다, 벽 뒤에 두는것이 좋습니다. -block.sniperturret.name = 레일건 포탑 -block.sniperturret.fulldescription = 고급 장거리 포탑.\n탄약에 강철을 사용합니다.\n\n매우 높은 데미지를 입힐 수 있지만 발사 속도는 낮습니다.\n사용 범위에 따라 적의 공격 범위 밖에서 공격할 수 있습니다. -block.mortarturret.name = 플랭크 포탑 -block.mortarturret.fulldescription = 고급형이자 정확도가 낮은 스플래쉬 데미지 포탑.\n탄약에 석탄을 사용합니다.\n\n파편으로 폭발하는 총알을 사용하고. 많은 적군에게 유용합니다. -block.laserturret.name = 레이저 포탑 -block.laserturret.fulldescription = 고급 단일 대상 공격 포탑.\n전력을 사용합니다.\n\n중간 크기의 사거리를 가지고 있고 절대 빗나가지 않습니다. -block.waveturret.name = 테슬라 포탑 -block.waveturret.fulldescription = 고급 다중 타겟 포탑.\n전력을 사용합니다.\n\n중간크기의 사거리를 가지고 있으며. 절대 빗나가지 않으므로 걱정할 염려가 없습니다.\n데미지는 거의 없지만 연속공격으로 여러 명의 적들을 동시에 공격 할 수 있습니다. -block.plasmaturret.name = 플라즈마 포탑 -block.plasmaturret.fulldescription = 포탑의 최고급 버전.\n석탄을 탄약으로 사용합니다.\n\n근접 사격 터렛의 끝판왕이며, 엄청나게 높은 데미지와 근거리와 중거리 사이 정도의 사거리를 가지고 있습니다. -block.chainturret.name = 체인 포탑 -block.chainturret.fulldescription = 궁국의 초고속 포탑.\n토륨을 탄약으로 사용합니다.\n\n엄청나게 빠른 공격속도를 가지고 있고, 중간 크기의 사거리를 가지고 있습니다.\n2x2 크기의 포탑입니다. -block.titancannon.name = 타이탄 캐논 -block.titancannon.fulldescription = 궁극의 장거리 포탑.\n토륨을 탄약으로 사용합니다.\n중간 수준의 사격 속도를 가지고 있으며 사거리가 매우 깁니다.\n\n3x3 크기의 포탑입니다. -block.playerspawn.name = 플레이어 스폰 지점 -block.enemyspawn.name = 적 스폰 지점 +text.about=제작자 : [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[] +text.credits=제작자 +text.discord=Mindustry Discord 에 참여하세요! +text.link.discord.description=공식 Mindustry Discord 채팅방 +text.link.github.description=게임 소스코드 +text.link.dev-builds.description=개발중인 빌드 +text.link.trello.description=다음 계획된 기능들을 게시한 공식 trello 보드 +text.link.itch.io.description=PC 버전 다운로드 HTML5 버전이 있는 itch.io 사이트 +text.link.google-play.description=Google 플레이 스토어 등록 정보 +text.link.wiki.description=공식 Mindustry 위키 +text.linkfail=링크를 여는데 실패했습니다!URL이 기기의 클립보드에 복사되었습니다. +text.editor.web=HTML5 버전은 에디터 기능을 지원하지 않습니다!게임을 다운로드 한 뒤에 사용 해 주세요. +text.web.unsupported=HTML5 버전은 이 기능을 지원하지 않습니다!게임을 다운로드 한 뒤에 사용 해 주세요. +text.multiplayer.web=이 버전은 멀티플레이를 지원하지 않습니다!멀티플레이를 웹 브라우저에서 즐기고 싶다면, itch.io 페이지에서 \"multiplayer web version\" 링크로 들어가면 됩니다. +text.host.web=HTML5 버전은 게임 호스팅을 지원하지 않습니다!게임을 다운로드 한 뒤에 사용 해 주세요. +text.gameover=코어가 터졌습니다. 게임 오버! +text.highscore=[YELLOW]최고점수 달성! +text.lasted=마지막으로 달성한 웨이브 +text.level.highscore=최고 점수 : [accent]{0} +text.level.delete.title=삭제 확인 +text.map.delete=정말로 \"[orange]{0}[]\" 맵을 삭제하시겠습니까? +text.level.select=맵 선택 +text.level.mode=게임모드: +text.construction.title=블록 배치 안내서 +text.construction=[accent]블록 배치 모드[]를 선택하셨습니다.\n\n블록을 설치하고 싶으면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 배치 작업을 진행할 것입니다.\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요. \n- [accent]블록을 넓게 배치[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.- [accent]블록을 한줄로 배치[]하고 싶다면 배치하고 싶은 시작 영역을 한번 탭 하고 길게 누르면서 드래그 하면 됩니다. \n- [accent]블록 배치 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. +text.deconstruction.title=블록 삭제 안내서 +text.deconstruction=[accent]블록 삭제 모드[]를 선택하셨습니다\n블록을 삭제하고 싶다면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 파괴 작업을 진행할 것입니다.\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요- [accent]블록을 넓은 범위로 삭제[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.- [accent]블록 삭제 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. +text.showagain=다음 세션에서 이 메세지를 표시하지 않습니다 +text.unlocks=잠금 해제 +text.savegame=게임 저장 +text.loadgame=게임 불러오기 +text.joingame=게임 참가 +text.addplayers=플레이어 추가/제거 +text.newgame=새 게임 +text.quit=나가기 +text.maps=맵 +text.maps.none=[LIGHT_GRAY]맵을 찾을 수 없습니다! +text.about.button=정보 +text.name=이름: +text.unlocked=새 블록이 잠금 해제되었습니다! +text.unlocked.plural=새 블록이 잠금 해제되었습니다! +text.players={0} 플레이어 온라인 +text.players.single={0} 플레이어 온라인 +text.server.mismatch=패킷 오류: 클라이언트와 서버 버전이 일치하지 않습니다.자신이 서버를 호스트하거나 최신 버전을 사용 해 주세요! +text.server.closing=[accent]서버 닫는중... +text.server.kicked.kick=당신은 서버에서 추방되었습니다! +text.server.kicked.fastShoot=당신은 총을 너무 빨리 발사했습니다. +text.server.kicked.invalidPassword=알 수 없는 비밀번호 입니다! +text.server.kicked.clientOutdated=오래된 버전의 클라이언트 입니다! 게임을 업데이트 하세요! +text.server.kicked.serverOutdated=오래된 버전의 서버입니다! 서버 호스트 관리자에게 문의하세요! +text.server.kicked.banned=당신은 서버에서 밴 망치를 맞아 차단당했습니다. +text.server.kicked.recentKick=당신은 방금 추방처리 되었습니다.잠시 기다린 후에 접속 해 주세요. +text.server.kicked.nameInUse=이 닉네임이 이미 서버에서 사용중입니다. +text.server.kicked.nameEmpty=닉네임에는 반드시 영어 또는 숫자가 있어야 합니다. +text.server.kicked.idInUse=당신은 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. +text.server.kicked.customClient=이 서버는 커스텀 빌드를 지원하지 않습니다. 공식 버전을 사용하세요. +text.server.connected={0} 님이 접속했습니다. +text.server.disconnected={0} 님이 나갔습니다. +text.nohost=커스텀 맵을 호스트 할 수 없습니다! +text.host.info=[accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 과 [scarlet]6568[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고 : LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. +text.join.info=여기서 [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원됩니다.\n\n[LIGHT_GRAY]참고 : 여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속할려면 서버장에게 IP를 요청해야 합니다. +text.hostserver=서버 열기 +text.host=호스트 +text.hosting=[accent]서버 여는중.. +text.hosts.refresh=새로고침 +text.hosts.discovering=LAN 게임 찾기 +text.server.refreshing=서버 목록 새로고치는중... +text.hosts.none=[lightgray]LAN 게임을 찾을 수 없습니다! +text.host.invalid=[scarlet]서버에 연결할 수 없습니다! +text.server.friendlyfire=팀킬 +text.trace=플레이어 추적 +text.trace.playername=플레이어 이름: [accent]{0} +text.trace.ip=IP : [accent]{0} +text.trace.id=고유 ID: [accent]{0} +text.trace.android=Android 클라이언트 : [accent]{0} +text.trace.modclient=수정된 클라이언트 : [accent]{0} +text.trace.totalblocksbroken=총 블럭 파괴 수: [accent]{0} +text.trace.structureblocksbroken=총 구조 블럭 파괴 수: [accent]{0} +text.trace.lastblockbroken=마지막으로 파괴한 블럭: [accent]{0} +text.trace.totalblocksplaced=총 설치한 블럭 수: [accent]{0} +text.trace.lastblockplaced=마지막으로 설치한 블록: [accent]{0} +text.invalidid=잘못된 클라이언트 ID 입니다! 공식 Mindustry 으로 버그 보고서를 제출 해 주세요. +text.server.bans=차단된 유저 +text.server.bans.none=차단된 플레이어가 없습니다. +text.server.admins=관리자들 +text.server.admins.none=관리자가 없습니다! +text.server.add=서버 추가 +text.server.delete=이 서버를 삭제 하시겠습니까? +text.server.hostname=호스트: {0} +text.server.edit=서버 수정 +text.server.outdated=[crimson]서버 버전이 낮습니다![] +text.server.outdated.client=[Crimson]클라이언트 버전이 낮습니다![] +text.server.version=[lightgray]버전 : {0} +text.server.custombuild=[yellow]커스텀 서버 +text.confirmban=이 플레이어를 차단하시겠습니까? +text.confirmunban=이 플레이어를 차단하시겠습니까? +text.confirmadmin=이 플레이어를 관리자로 설정 하시겠습니까? +text.confirmunadmin=이 플레이어의 관리자 상태를 해제하시겠습니까? +text.joingame.title=게임 참가 +text.joingame.ip=IP: +text.disconnect=서버와 연결이 해제되었습니다. +text.disconnect.data=맵 데이터를 불러오지 못했습니다! +text.connecting=[accent]연결중... +text.connecting.data=[accent]월드 데이터 로딩중... +text.connectfail=[crimson]{0}[orange] 서버에 연결하지 못했습니다.[] +text.server.port=포트: +text.server.addressinuse=이 주소는 이미 사용중입니다! +text.server.invalidport=포트 번호가 잘못되었습니다. +text.server.error=[crimson]{0}[orange]서버를 호스팅 하는데 오류가 발생했습니다.[] +text.save.new=새로 저장\n +text.save.overwrite=이 저장 슬롯을 덮어씌우겠습니까?\n +text.overwrite=덮어쓰기\n +text.save.none=저장 파일을 찾지 못했습니다!\n +text.saveload=[accent]저장중...\n +text.savefail=게임을 저장하지 못했습니다!\n +text.save.delete.confirm=이 저장파일을 삭제 하시겠습니까?\n +text.save.delete=삭제\n +text.save.export=저장파일 내보내기\n +text.save.import.invalid=[orange]저장 상태가 정상이 아닙니다! +text.save.import.fail=[crimson]저장파일을 불러오지 못함: [orange]{0}\n +text.save.export.fail=[crimson]저장파일을 내보내지 못함: [orange]{0} +text.save.import=저장파일 불러오기\n +text.save.newslot=저장 파일이름 :\n +text.save.rename=이름 변경\n +text.save.rename.text=새 이름 :\n +text.selectslot=저장슬롯을 선택하십시오.\n +text.slot=[accent]{0}번째 슬롯\n +text.save.corrupted=[orange]세이브 파일이 손상되었거나 잘못된 파일입니다!만약 게임을 업데이트 했다면 이것은 아마 저장 형식 변경일 것이고, 이것은 버그가 [scarlet]아닙니다[].\n\n +text.empty=<비어있음>\n +text.on=켜기\n +text.off=끄기\n +text.save.autosave=자동저장: {0} +text.save.map=맵 : {0} +text.save.wave={0} 웨이브 +text.save.difficulty=난이도: {0} +text.save.date=마지막 저장 날짜 : {0} +text.confirm=확인 +text.delete=삭제\n +text.ok=승인 +text.open=열기 +text.cancel=취소 +text.openlink=링크 열기 +text.copylink=링크 복사 +text.back=뒤로가기 +text.quit.confirm=정말로 종료하시겠습니까? +text.changelog.title=변경사항 +text.changelog.loading=변경사항 가져오는중... +text.changelog.error.android=[orange]게임 변경사항은 가끔 Android 4.4 이하에서 작동하지 않습니다.이것은 내부 Android 버그 때문입니다. +text.changelog.error.ios=[orange]현재 iOS에서는 변경 사항을 지원하지 않습니다. +text.changelog.error=[scarlet]게임 변경사항을 가져오는 중 오류가 발생했습니다![]\n인터넷 연결을 확인하십시오. +text.changelog.current=[orange][[현재 버전] +text.changelog.latest=[orange][[최신 버전] +text.loading=[accent]불러오는중... +text.saving=[accent]저장중...\n +text.wave=[orange]{0} 웨이브 +text.wave.waiting=다음 웨이브 시작까지 {0}초 +text.waiting=기다리는중... +text.enemies=남은 몹 : {0} +text.enemies.single=몹이 {0}마리 남아있음 +text.loadimage=사진 불러오기 +text.saveimage=사진 저장 +text.unknown=알 수 없음 +text.custom=커스텀 +text.builtin=내장 +text.map.delete.confirm=이 맵을 삭제하시겠습니까? 이 명령은 취소할 수 없습니다! +text.map.random=[accent]랜덤 맵 +text.map.nospawn=이 맵에는 플레이어가 스폰 할 코어가 없습니다! 맵 편집기에서 [ROYAL]파란색[]코어를 맵에 추가하세요. +text.editor.slope=\\ +text.editor.openin=편집기 열기 +text.editor.oregen=광물 무작위 생성 +text.editor.oregen.info=광물 무작위 생성: +text.editor.mapinfo=맵 정보 +text.editor.author=만든이: +text.editor.description=설명: +text.editor.name=이름: +text.editor.teams=팀 +text.editor.elevation=높이 +text.editor.badsize=[orange]사진 크기가 잘못되었습니다![]유효한 맵 크기 : {0} +text.editor.errorimageload=[orange]{0}[] 파일을 불러오는데 오류가 발생했습니다. +text.editor.errorimagesave=[orange]{0}[] 파일 저장중 오류가 발생했습니다. +text.editor.generate=생성 +text.editor.resize=맵 크기조정 +text.editor.loadmap=맵 불러오기 +text.editor.savemap=맵 저장 +text.editor.saved=저장됨! +text.editor.save.noname=지도에 이름이 없습니다! '맵 정보' 메뉴에서 설정하세요. +text.editor.save.overwrite=이 맵의 이름은 기존에 있던 맵을 덮어씁니다! '맵 정보' 메뉴에서 다른 이름을 선택하세요. +text.editor.import.exists=[scarlet]맵을 불러올 수 없음:[] 기존에 있던 '{0}' 맵이 이미 존재합니다! +text.editor.import=가져오기 +text.editor.importmap=맵 가져오기 +text.editor.importmap.description=이미 존재하는 맵 가져오기 +text.editor.importfile=파일 가져오기 +text.editor.importfile.description=외부 맵 파일 가져오기 +text.editor.importimage=지형 사진 가져오기 +text.editor.importimage.description=외부 맵 이미지 파일 가져오기 +text.editor.export=내보내기 +text.editor.exportfile=파일 내보내기 +text.editor.exportfile.description=맵 파일 내보내기 +text.editor.exportimage=지형 이미지 내보내기 +text.editor.exportimage.description=맵 이미지 파일 내보내기 +text.editor.loadimage=지형 가져오기 +text.editor.saveimage=지형 내보내기 +text.editor.unsaved=[scarlet]변경사항을 저장하지 않았습니다![]\n정말로 나가시겠습니까?\n +text.editor.resizemap=맵 크기 조정 +text.editor.mapname=맵 이름: +text.editor.overwrite=[accept]경고!이 명령은 기존 맵을 덮어씌우게 됩니다.\n +text.editor.overwrite.confirm=[scarlet]경고![] 이 이름을 가진 맵이 이미 있습니다. 덮어 쓰시겠습니까? +text.editor.selectmap=불러올 맵 선택: +text.width=넓이: +text.height=높이: +text.menu=메뉴 +text.play=플레이 +text.load=불러오기 +text.save=저장 +text.fps={0} FPS +text.tps={0} TPS +text.ping=핑 : {0}ms +text.language.restart=언어를 변경하려면 게임을 다시 시작 해 주세요. +text.settings.language=언어 +text.settings=설정 +text.tutorial=게임 방법 +text.editor=편집기 +text.mapeditor=맵 편집기 +text.donate=기부 +text.settings.reset=설정 초기화 +text.settings.rebind=키 재설정 +text.settings.controls=컨트롤 +text.settings.game=게임 +text.settings.sound=소리 +text.settings.graphics=화면 +text.upgrades=강화 +text.purchased=[LIME]생성됨! +text.weapons=무기 +text.paused=일시 정지 +text.yes=예 +text.no=아니오 +text.info.title=[accent]정보 +text.error.title=[crimson]오류가 발생했습니다. +text.error.crashtitle=오류가 발생했습니다. +text.blocks.blockinfo=블록 정보 +text.blocks.powercapacity=최대 전력 용량 +text.blocks.powershot=1발당 파워 소모량 +text.blocks.targetsair=표적 공기 +text.blocks.itemspeed=유닛 이동 속도 +text.blocks.shootrange=공격 범위 +text.blocks.size=블록 크기 +text.blocks.liquidcapacity=최대 액체 용량 +text.blocks.maxitemssecond=최대 아이템 보관량 +text.blocks.powerrange=전력 범위 +text.blocks.poweruse=전력 사용 +text.blocks.inputitemcapacity=입력 아이템 용량 +text.blocks.outputitemcapacity=입력 아이템 용량 +text.blocks.itemcapacity=품목 용량 +text.blocks.maxpowergeneration=최대 발전량 +text.blocks.powertransferspeed=전력 전송량 +text.blocks.craftspeed=생산 속도 +text.blocks.inputliquid=입력 액체 +text.blocks.inputliquidaux=보조 액체 +text.blocks.inputitem=입력 아이템 +text.blocks.inputitems=입력 아이템들 +text.blocks.outputitem=출력 아이템 +text.blocks.drilltier=드릴 +text.blocks.drillspeed=기본 드릴 속도 +text.blocks.liquidoutput=액체 출력 +text.blocks.liquiduse=액체 사용 +text.blocks.coolant=냉각제 +text.blocks.coolantuse=냉각수 사용 +text.blocks.inputliquidfuel=연료 액 +text.blocks.liquidfueluse=액체 연료 사용 +text.blocks.explosive=이게 터지면 펑 터지면서 주변 블록에게 피해를 입힙니다! +text.blocks.health=체력 +text.blocks.inaccuracy=빗맞을 확률 +text.blocks.shots=총알 +text.blocks.reload=재장전 +text.blocks.inputfuel=연료 +text.blocks.fuelburntime=연료 연소 시간 +text.blocks.inputcapacity=입력 용량 +text.blocks.outputcapacity=출력 용량 +text.blocks.requird=요구사항: + +text.unit.blocks=블록들 +text.unit.powersecond=초당 전력 단위 +text.unit.liquidsecond=액체 단위 / 초 +text.unit.itemssecond=항목 / 초 +text.unit.pixelssecond=초당 픽셀 +text.unit.liquidunits=액상 단위 +text.unit.powerunits=전원 장치 +text.unit.degrees=도 +text.unit.seconds=초 +text.unit.none= +text.unit.items=아이템 + +text.category.general=일반 +text.category.power=전력 +text.category.liquids=액체 +text.category.items=아이템 +text.category.crafting=제작 +text.category.shooting=발사 +setting.difficulty.easy=쉬움 +setting.difficulty.normal=보통 +setting.difficulty.hard=어려움 +setting.difficulty.insane=[#1E90FF]K[#ADFF2F]O[#FFB6C1]R[#B0C4DE]E[#FF4500]A +setting.difficulty.purge=[#1E90FF]K[#ADFF2F]O[#FFB6C1]R[#B0C4DE]E[#FF4500]A +setting.difficulty.name=난이도: +setting.screenshake.name=화면 흔들기 +setting.indicators.name=적 위치 표시 화살표 +setting.effects.name=화면 효과 +setting.sensitivity.name=컨트롤러 감도 +setting.saveinterval.name=자동저장 간격 +setting.seconds={0}초 +setting.fullscreen.name=전체 화면 +setting.multithread.name=멀티 스레드 +setting.fps.name=FPS 표시 +setting.vsync.name=VSync 활성화 +setting.lasers.name=파워 레이져 표시 +setting.healthbars.name=몹 체력바 표시 +setting.minimap.name=미니맵 보기 +setting.musicvol.name=음악 크기 +setting.mutemusic.name=음소거 +setting.sfxvol.name=효과음 크기 +setting.mutesound.name=소리 끄기 +map.maze.name=미로 +map.fortress.name=요새 +map.sinkhole.name=싱크홀 +map.caves.name=동굴 +map.volcano.name=화산 +map.caldera.name=칼데라 +map.scorch.name=타버림 +map.desert.name=사막 +map.island.name=섬 +map.grassland.name=목초지 +map.tundra.name=툰트라 +map.spiral.name=나선 +map.tutorial.name=게임 방법 +text.keybind.title=키 바인딩 +keybind.move_x.name=오른쪽/왼쪽 이동 +keybind.move_y.name=위쪽/아래쪽 이동 +keybind.select.name=선택 +keybind.break.name=파괴 +keybind.shoot.name=사격 +keybind.zoom_hold.name=길게눌러 확대 +keybind.zoom.name=확대 +keybind.block_info.name=블럭 정보 +keybind.menu.name=메뉴 +keybind.pause.name=일시중지 +keybind.dash.name=달리기 +keybind.chat.name=채팅 +keybind.player_list.name=플레이어 목록 +keybind.console.name=콘솔 +keybind.rotate_alt.name=rotate_alt +keybind.rotate.name=회전 +mode.text.help.title=도움말 +mode.waves.name=웨이브 +mode.waves.description=이것은 일반 모드입니다. 제한된 자원과 자동으로 다음 웨이브가 시작됩니다. +mode.sandbox.name=샌드박스 +mode.sandbox.description=무한한 자원과 다음 웨이브 시작을 위한 타이머가 없습니다. +mode.freebuild.name=자유 건축 +mode.freebuild.description=제한된 자원과 다음 웨이브 시작을 위한 타이머가 없습니다. + +content.item.name=아이템 +content.liquid.name=액체 +content.unit-type.name=종류 +content.recipe.name=블록들 + +item.stone.name=돌 +item.stone.description=흔히 찾을 수 있는 자원. 바닥에서 돌을 캐거나 용암을 사용하여 얻을 수 있습니다. +item.tungsten.name=텅스텐 +item.tungsten.description=일반적이지만 매우 유용한 건축 재료. 드릴 및 생산 건물, 제련소와 같은 내열성 블록에 사용됩니다. +item.lead.name=리드 +item.lead.description=기본적인 시작 자원. 전자 및 액체 수송 블록에서 광범위하게 사용됩니다. +item.coal.name=석탄 +item.coal.description=일반적이고 쉽게 이용할 수 있는 연료. +item.carbide.name=합금 +item.carbide.description=텅스텐과 탄소로 만든 합금. 고급 운송 블록 및 상위 티어 드릴에 사용됩니다. +item.titanium.name=티타늄 +item.titanium.description=물 운반이나 드릴, 비행기등에서 재료로 사용되는 자원입니다. +item.thorium.name=토륨 +item.thorium.description=건물 탄약 또는 핵연료로 사용되는 방사성 금속. +item.silicon.name=실리콘 +item.silcion.description=매우 유용한 반도체로, 태양 전지 패널과 복잡한 전자 제품에 응용할 수 있습니다. +item.plastanium.name=플라스타늄 +item.plastanium.description=고급 항공기 및 분열 탄약에 사용되는 가벼운 연성 재료. +item.phase-matter.name=메타 +item.surge-alloy.name=설합금 +item.biomatter.name=바이오메터 +item.biomatter.description=이것은 유기농 덤불입니다! 석유로 전환하거나 기본 연료로 사용됩니다. +item.sand.name=모래 +item.sand.description=합금 및 플럭스 모두에서 제련시 광범위하게 사용되는 일반적인 재료. +item.blast-compound.name=폭발 화합물 +item.blast-compound.description=폭탄 및 폭발물에 사용되는 휘발성 화합물.연료로 불을 낼 수 있지만, 별로 추천하지는 않습니다. +item.pyratite.name=피러레이트 +item.pyratite.description=화염 무기에 사용되는 엄청난 가연성 물질. + +liquid.water.name=물 +liquid.lava.name=용암 +liquid.oil.name=석유 +liquid.cryofluid.name=크라이오플루드 + +text.item.explosiveness=[LIGHT_GRAY]폭발력 : {0} +text.item.flammability=[LIGHT_GRAY]인화성 : {0} +text.item.radioactivity=[LIGHT_GRAY]방사능 : {0} +text.item.fluxiness=[LIGHT_GRAY]플렉스 파워 : {0} +text.item.hardness=[LIGHT_GRAY]강도 : {0} +text.liquid.heatcapacity=[LIGHT_GRAY]발열 용량 : {0} +text.liquid.viscosity=[LIGHT_GRAY]점도 : {0} +text.liquid.temperature=[LIGHT_GRAY]온도 : {0} +block.tungsten-wall.name=텅스텐 벽 +block.tungsten-wall-large.name=큰 텅스텐 벽 +block.carbide-wall.name=합금벽 +block.carbide-wall-large.name=대형 합금벽 +block.thorium-wall.name=토룸 벽 +block.thorium-wall-large.name=대형 토륨 벽 +block.door.name=문 +block.door-large.name=큰 문 +block.duo.name=샷건 +block.scorch.name=스코치 +block.hail.name=헤일 +block.lancer.name=랜서 +block.conveyor.name=컨베이어 +block.titanium-conveyor.name=티타늄 컨베이어 +block.junction.name=교차기 +block.splitter.name=스플리터 +block.splitter.description=아이템을 넣는 즉시 컨베이어를 반대 방향으로 바꾼 후 내보냅니다. +block.router.name=분배기 +block.router.description=아이템을 넣으면 다른 방향으로 아이템을 번갈아서 내보냅니다. +block.distributor.name=디스토이어 +block.distributor.description=아이템을 8방향으로 나눌 수있는 스플리터. +block.sorter.name=필터 +block.sorter.description=아이템을 받아서 설정된 아이템일 경우 바로 앞으로 통과하며, 그렇지 않을 경우 옆으로 통과합니다. +block.overflow-gate.name=오버플로 게이트 +block.overflow-gate.description=정면 경로가 차단된 경우 왼쪽과 오른쪽으로만 출력하는 복합 스플리터와 분배기 입니다. +block.bridgeconveyor.name=터널 +block.bridgeconveyor.description=최대 2블록을 건너 뛰고 자원을 운반하게 해 주는 블럭. +block.smelter.name=제련소 +block.arc-smelter.name=아크 제련소 +block.silicon-smelter.name=실리콘 제련소 +block.phase-weaver.name=펄스 위버 +block.pulverizer.name=분쇄기 +block.cryofluidmixer.name=크라이오플루드 혼합기 +block.melter.name=멜터 +block.incinerator.name=소각로 +block.biomattercompressor.name=바이오매터 압축기 +block.separator.name=셉터 +block.centrifuge.name=원심 분리기 +block.power-node.name=전력 노드 +block.power-node-large.name=대형 전력 노드 +block.battery.name=배터리 +block.battery-large.name=대형 배터리 +block.combustion-generator.name=연소 발전기 +block.turbine-generator.name=터빈 발전기 +block.tungsten-drill.name=텅스텐 드릴 +block.carbide-drill.name=합금 드릴 +block.laser-drill.name=레이저 드릴 +block.water-extractor.name=물 추출기 +block.cultivator.name=경운기 +block.dart-ship-factory.name=다트 선박 공장 +block.delta-mech-factory.name=델타 메크 공장 +block.dronefactory.name=드론 공장 +block.repairpoint.name=수리 포인트 +block.resupplypoint.name=재공급 포인트 +block.conduit.name=도관 +block.pulseconduit.name=펄스 도관 +block.liquidrouter.name=액체 분배기 +block.liquidtank.name=물탱크 +block.liquidjunction.name=액체 교차기 +block.bridgeconduit.name=브릿지 도관 +block.mechanical-pump.name=기계 펌프 +block.itemsource.name=아이템 소스 +block.itemvoid.name=아이템 무효 +block.liquidsource.name=액체 소스 +block.powervoid.name=무효 전력 +block.powerinfinite.name=무한한 힘 +block.unloader.name=언로더 +block.sortedunloader.name=정렬된 언로더 +block.vault.name=Vault +block.wave.name=웨이브 +block.swarmer.name=스워머 +block.salvo.name=살보 +block.ripple.name=라이플 +block.phase-conveyor.name=펄스 컨베이어 +block.bridge-conveyor.name=터널 +block.plastanium-compressor.name=플라스터늄 압축기 +block.pyratite-mixer.name=피터레이트 혼합기 +block.blast-mixer.name=블래스트 혼합기 +block.solidifer.name=고체 +block.solar-panel.name=태양 전지 패널 +block.solar-panel-large.name=대형 태양 전지판 +block.oil-extractor.name=오일 추출기 +block.javelin-ship-factory.name=창 던지기 선박 공장 +block.drone-factory.name=드론 팩토리 +block.fabricator-factory.name=Fabricator 공장 +block.repair-point.name=수리 점 +block.resupply-point.name=재 공급 포인트 +block.pulse-conduit.name=펄스 도관 +block.phase-conduit.name=위상 도관 +block.liquid-router.name=액체 라우터 +block.liquid-tank.name=액체 탱크 +block.liquid-junction.name=액체 교차기 +block.bridge-conduit.name=브릿지 도관 +block.rotary-pump.name=로타리 펌프 +block.nuclear-reactor.name=핵발전소 +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. \ No newline at end of file diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index fb5027cddf..ef022067b0 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -1,488 +1,495 @@ -text.about = Stworzony przez [ROYAL] Anuken. []\nPierwotnie wpis w [orange] GDL [] MM Jam.\n\nNapisy:\n- SFX wykonane z pomocą [YELLOW] bfxr []\n- Muzyka wykonana przez [GREEN] RoccoW [] / znaleziona na [lime] FreeMusicArchive.org []\n\nSpecjalne podziękowania dla:\n- [coral] MitchellFJN []: obszerne testowanie i feedback\n- [niebo] Luxray5474 []: prace związane z wiki, pomoc z kodem\n- Wszystkich beta testerów na itch.io i Google Play\n -text.discord = Odwiedź nasz serwer Discord -text.gameover = Rdzeń został zniszczony. -text.highscore = [YELLOW] Nowy rekord! -text.lasted = Wytrwałeś do fali -text.level.highscore = Rekord: [accent]{0} -text.level.delete.title = Potwierdź kasowanie -text.level.delete = Czy na pewno chcesz usunąć mapę \"[orange]{0}\"? -text.level.select = Wybrany poziom -text.level.mode = Tryb gry: -text.savegame = Zapisz Grę -text.loadgame = Wczytaj grę -text.joingame = Gra wieloosobowa -text.quit = Wyjdź -text.about.button = O grze -text.name = Nazwa: -text.public = Publiczny -text.players = {0} graczy online -text.server.player.host = {0} (host) -text.players.single = {0} gracz online -text.server.mismatch = Błąd pakietu: możliwa niezgodność wersji klienta/serwera.\nUpewnij się, że Ty i host macie najnowszą wersję Mindustry! -text.server.closing = [accent] Zamykanie serwera ... -text.server.kicked.kick = Zostałeś wyrzucony z serwera! -text.server.kicked.invalidPassword = Nieprawidłowe hasło! -text.server.kicked.clientOutdated = Nieaktualna gra! Zaktualizują ją! -text.server.kicked.serverOutdated = Nieaktualna gra! Zaktualizują ją! -text.server.connected = {0} dołączył do gry . -text.server.disconnected = {0} został rozłączony. -text.nohost = Nie można hostować serwera na mapie niestandardowej! -text.hostserver = Serwer hosta -text.host = Host -text.hosting = [accent] Otwieranie serwera ... -text.hosts.refresh = Odśwież -text.hosts.discovering = Wyszukiwanie gier w sieci LAN -text.server.refreshing = Odświeżanie serwera -text.hosts.none = [lightgray] Brak serwerów w sieci LAN! -text.host.invalid = [scarlet] Nie można połączyć się z hostem. -text.server.friendlyfire = Bratobójczy ogień -text.server.add = Dodaj serwer -text.server.delete = Czy na pewno chcesz usunąć ten serwer? -text.server.hostname = Host: {0} -text.server.edit = Edytuj serwer -text.joingame.byip = Dołącz przez IP... -text.joingame.title = Dołącz do gry -text.joingame.ip = IP: -text.disconnect = Rozłączony. -text.connecting = [accent]Łączenie ... -text.connecting.data = [accent]Ładowanie danych świata... -text.connectfail = [crimson]Nie można połączyć się z serwerem: [orange] {0} -text.server.port = Port: -text.server.addressinuse = Adres jest już w użyciu! -text.server.invalidport = Nieprawidłowy numer portu. -text.server.error = [crimson] Błąd hostowania serwera: [orange] {0} -text.tutorial.back = < Cofnij -text.tutorial.next = Dalej > -text.save.new = Nowy zapis -text.save.overwrite = Czy na pewno chcesz nadpisać zapis gry? -text.overwrite = Nadpisz -text.save.none = Nie znaleziono zapisów gry! -text.saveload = [akcent]Zapisywanie... -text.savefail = Nie udało się zapisać gry! -text.save.delete.confirm = Czy na pewno chcesz usunąć ten zapis gry? -text.save.delete = Usuń -text.save.export = Eksportuj -text.save.import.invalid = [orange]Zapis gry jest niepoprawny! -text.save.import.fail = [crimson]Nie udało się zaimportować zapisu: [orange] {0} -text.save.export.fail = [crimson]Nie można wyeksportować zapisu: [orange] {0} -text.save.import = Importuj -text.save.newslot = Zapisz nazwę: -text.save.rename = Zmień nazwę -text.save.rename.text = Zmień nazwę -text.selectslot = Wybierz zapis. -text.slot = [accent]Slot {0} -text.save.corrupted = [orange]Zapis gry jest uszkodzony lub nieprawidłowy! -text.empty = -text.on = Włączone -text.off = Wyłączone -text.save.autosave = Zapisywanie automatyczne -text.save.map = Mapa: {0} -text.save.wave = Fala: {0} -text.save.date = Ostatnio zapisano: {0} -text.confirm = Potwierdź -text.delete = Usuń -text.ok = Ok -text.open = Otwórz -text.cancel = Anuluj -text.openlink = Otwórz link -text.back = Wróć -text.quit.confirm = Czy na pewno chcesz wyjść? -text.loading = [accent]Ładowanie ... -text.wave = [orange]Fala {0} -text.wave.waiting = Fala w {0} -text.waiting = Oczekiwanie... -text.enemies = {0} wrogów -text.enemies.single = {0} wróg -text.loadimage = Załaduj obraz -text.saveimage = Zapisz obraz -text.editor.badsize = [orange]Nieprawidłowe wymiary obrazu![]\nWymiary poprawne: {0} -text.editor.errorimageload = Błąd podczas ładowania pliku obrazu: [orange]{0} -text.editor.errorimagesave = Błąd podczas zapisywania pliku obrazu: [orange]{0} -text.editor.generate = Generuj -text.editor.resize = Zmień rozmiar -text.editor.loadmap = Załaduj mapę -text.editor.savemap = Zapisz mapę -text.editor.loadimage = Załaduj obraz -text.editor.saveimage = Zapisz obraz -text.editor.unsaved = [scarlet]Masz niezapisane zmiany![]\nCzy na pewno chcesz wyjść? -text.editor.brushsize = Rozmiar pędzla: {0} -text.editor.noplayerspawn = Ta mapa nie ma ustawionego spawnu gracza! -text.editor.manyplayerspawns = Mapy nie mogą mieć więcej niż jeden punkt spawnu gracza! -text.editor.manyenemyspawns = Nie może mieć więcej niż {0} punktów spawnu wroga! -text.editor.resizemap = Zmień rozmiar mapy -text.editor.resizebig = [scarlet]Uwaga![]\nMapy większe niż 256 jednostek mogą przycinać i być niestabilne. -text.editor.mapname = Nazwa mapy: -text.editor.overwrite = [accent]Uwaga!\nSpowoduje to nadpisanie istniejącej mapy. -text.editor.failoverwrite = [crimson]Nie można nadpisać mapy podstawowej! -text.editor.selectmap = Wybierz mapę do załadowania: -text.width = Szerokość: -text.height = Wysokość: -text.randomize = Wylosuj -text.apply = Zastosuj -text.update = Zaktualizuj -text.menu = Menu -text.play = Graj -text.load = Wczytaj -text.save = Zapisz -text.language.restart = Uruchom grę ponownie aby ustawiony język zaczął funkcjonować. -text.settings.language = Język -text.settings = Ustawienia -text.tutorial = Poradnik -text.editor = Edytor -text.mapeditor = Edytor map -text.donate = Wspomóż nas -text.settings.reset = Przywróć domyślne -text.settings.controls = Sterowanie -text.settings.game = Gra -text.settings.sound = Dźwięk -text.settings.graphics = Grafika -text.upgrades = Ulepszenia -text.purchased = [LIME]Stworzono! -text.weapons = Bronie -text.paused = Wstrzymano -text.respawn = Odrodzenie za -text.info.title = [accent]Informacje -text.error.title = [crimson]Wystąpił błąd -text.error.crashmessage = [SCARLET]Wystąpił nieoczekiwany błąd, który spowodowałby awarię.[]\nProszę, powiadom dewelopera gry o tym błędzie, pisząc jak do niego doszło: [ORANGE]anukendev@gmail.com[] -text.error.crashtitle = Wystąpił błąd -text.mode.break = Tryb przerw: {0} -text.mode.place = Tryb układania: {0} -placemode.hold.name = linia -placemode.areadelete.name = obszar -placemode.touchdelete.name = Dotyk -placemode.holddelete.name = Przytrzymać -placemode.none.name = żaden -placemode.touch.name = Dotyk -placemode.cursor.name = kursor -text.blocks.extrainfo = [accent]Dodatkowe informacje o bloku: -text.blocks.blockinfo = Informacje o bloku -text.blocks.powercapacity = Moc znamionowa -text.blocks.powershot = moc / strzał -text.blocks.powersecond = moc / sekunda -text.blocks.powerdraindamage = siła ataku / obrażenia -text.blocks.shieldradius = Promień osłony -text.blocks.itemspeedsecond = prędkość ​​/ sekundy -text.blocks.range = Zakres -text.blocks.size = Rozmiar -text.blocks.powerliquid = moc / ciecz -text.blocks.maxliquidsecond = maksymalna ilość cieczy / sekunda -text.blocks.liquidcapacity = Pojemność cieczy -text.blocks.liquidsecond = ciecz / sekunda -text.blocks.damageshot = obrażenia / strzał -text.blocks.ammocapacity = Pojemność amunicji -text.blocks.ammo = Amunicja: -text.blocks.ammoitem = amunicja / przedmiot -text.blocks.maxitemssecond = Maksymalna liczba przedmiotów / Sekunda -text.blocks.powerrange = Zakres mocy -text.blocks.lasertilerange = Zasięg lasera -text.blocks.capacity = Wydajność -text.blocks.itemcapacity = Pojemność przedmiotów -text.blocks.maxpowergenerationsecond = maksymalne generowanie energii / sekunda -text.blocks.powergenerationsecond = wytwarzanie energii / sekunda -text.blocks.generationsecondsitem = sekunda / przedmiot -text.blocks.input = Wkład -text.blocks.inputliquid = Potrzebna ciecz -text.blocks.inputitem = Potrzebne przedmioty -text.blocks.output = Wyjście -text.blocks.secondsitem = sekundy / przedmiot -text.blocks.maxpowertransfersecond = maksymalny transfer mocy / sekundę -text.blocks.explosive = Wysoce wybuchowy! -text.blocks.repairssecond = naprawa / sekunda -text.blocks.health = Zdrowie -text.blocks.inaccuracy = Niedokładność -text.blocks.shots = Strzały -text.blocks.shotssecond = Strzały / Sekunda -text.blocks.fuel = Paliwo -text.blocks.fuelduration = Wydajność paliwa -text.blocks.maxoutputsecond = maksymalne wyjście / sekunda -text.blocks.inputcapacity = Pojemność wejściowa -text.blocks.outputcapacity = Wydajność wyjściowa -text.blocks.poweritem = moc / przedmiot -text.placemode = Tryb miejsca -text.breakmode = Tryb przerwania -text.health = Zdrowie: -setting.difficulty.easy = łatwy -setting.difficulty.normal = normalny -setting.difficulty.hard = trudny -setting.difficulty.insane = szalony -setting.difficulty.purge = Czystka -setting.difficulty.name = Poziom trudności -setting.screenshake.name = Trzęsienie się ekranu -setting.smoothcam.name = Płynna kamera -setting.indicators.name = Wskaźniki wroga -setting.effects.name = Wyświetlanie efektów -setting.sensitivity.name = Czułość kontrolera -setting.saveinterval.name = Interwał automatycznego zapisywania -setting.seconds = Sekundy -setting.fps.name = Widoczny licznik FPS -setting.vsync.name = Synchronizacja pionowa -setting.lasers.name = Pokaż lasery zasilające -setting.healthbars.name = Pokaż paski zdrowia jednostki -setting.pixelate.name = Rozpikselizowany obraz -setting.musicvol.name = Głośność muzyki -setting.mutemusic.name = Wycisz muzykę -setting.sfxvol.name = Głośność dźwięków -setting.mutesound.name = Wycisz dźwięki -map.maze.name = labirynt -map.fortress.name = twierdza -map.sinkhole.name = wgłębienie -map.caves.name = jaskinie -map.volcano.name = wulkan -map.caldera.name = kaldera -map.scorch.name = opalacz -map.desert.name = pustynia -map.island.name = wyspa -map.grassland.name = łąka -map.tundra.name = tundra -map.spiral.name = spirala -map.tutorial.name = Poradnik -tutorial.intro.text = [yellow]Witamy w poradniku do gry.[]\nAby rozpocząć, naciśnij \"Dalej\". -tutorial.moveDesktop.text = Aby się poruszać, użyj klawiszy [orange]W A S[] oraz [orange]D[]. Przytrzymaj [orange]shift[], aby przyśpieszyć.\nPrzytrzymując [orange]ctrl[] podczas kręcenia [orange]rolką myszy[] możesz zmieniać poziom przybliżenia mapy. -tutorial.shoot.text = Do celowania używasz kursora myszy.\n[orange]Lewy przycisk myszy[] służy do strzelania. Poćwicz na [yellow]celu[]. -tutorial.moveAndroid.text = Aby przesunąć widok, przeciągnij jednym palcem po ekranie. Ściśnij i przeciągnij, aby powiększyć lub pomniejszyć. -tutorial.placeSelect.text = Wybierz [yellow]przenośnik[] z menu blokowego w prawym dolnym rogu. -tutorial.placeConveyorDesktop.text = Użyj [orange]rolki myszy[] aby obrócić przenośnik [orange]do przodu[], a następnie umieść go w [yellow]oznaczonym miejscu[] za pomocą [orange]lewego przycisku myszy[]. -tutorial.placeConveyorAndroid.text = Użyj [orange]przycisk obracania[], aby obrócić przenośnik [orange]do przodu[]. Jednym palcem przeciągnij go na [yellow]wskazaną pozycję[], a następnie umieść go za pomocą [orange]znacznika wyboru[]. -tutorial.placeConveyorAndroidInfo.text = Możesz też nacisnąć ikonę celownika w lewym dolnym rogu, aby przełączyć na [pomarańczowy] [[tryb dotykowy] [] i umieścić bloki, dotykając ekranu. W trybie dotykowym bloki można obracać strzałką w lewym dolnym rogu. Naciśnij [żółty] następny [], aby go wypróbować. -tutorial.placeDrill.text = Teraz wybierz i umieść [yellow]wiertło do kamienia[] w oznaczonym miejscu. -tutorial.blockInfo.text = Jeśli chcesz się dowiedzieć więcej na temat wybranego bloku, kliknij [orange]znak zapytania[] w prawym górnym rogu, aby przeczytać jego opis. -tutorial.deselectDesktop.text = Możesz anulować wybór bloku za pomocą [orange]prawego przycisku myszy[]. -tutorial.deselectAndroid.text = Możesz odznaczyć blok, naciskając przycisk [orange]X[]. -tutorial.drillPlaced.text = Wiertło będzie teraz produkować [yellow]kamień[] i podawać go na przenośnik, który przeniesie go do [yellow]rdzenia[] -tutorial.drillInfo.text = Różne rudy wymagają różnych wierteł. Kamień wymaga wiertła do kamieniu, żelazo wymaga wiertła do żelaza, itd. -tutorial.drillPlaced2.text = Przeniesienie przedmiotów do rdzenia powoduje umieszczenie ich w [yellow]inwentarzu przedmiotów[] w lewym górnym rogu. Stawianie bloków te przedmioty zużywa. -tutorial.moreDrills.text = Możesz połączyć wiertła i przenośników w przedstawiony sposób: -tutorial.deleteBlock.text = Możesz usuwać bloki, klikając [orange]prawy przycisk myszy[] na bloku, który chcesz usunąć.\nSpróbuj usunąć [yellow]oznaczony[] przenośnik. -tutorial.deleteBlockAndroid.text = Możesz usuwać bloki za pomocą [orange]krzyżyka[] w [orange]menu przerywania[] w lewym dolnym rogu i stukając w blok.\nSpróbuj usunąć [yellow]oznaczony[] przenośnik. -tutorial.placeTurret.text = Teraz wybierz i umieść [yellow]działko[] w [yellow]zaznaczonym miejscu[]. -tutorial.placedTurretAmmo.text = Działko przyjmie teraz [yellow]amunicję[] z przenośnika. Możesz zobaczyć, ile ma amunicji, najeżdżając na działko kursorem i sprawdzając [green]zielony pasek[]. -tutorial.turretExplanation.text = Wieżyczki będą strzelać automatycznie do najbliższego wroga w zasięgu, o ile będą miały wystarczającą ilość amunicji. -tutorial.waves.text = Co każde [yellow]60[] sekund, fala [coral]wrogów[] pojawi się w określonym miejscu na mapie i spróbuje zniszczyć rdzeń. -tutorial.coreDestruction.text = Twoim celem jest [yellow]obrona rdzenia[]. Zniszczenie rdzenia jest równoznaczne z [coral]przegraną[]. -tutorial.pausingDesktop.text = Jeśli chcesz zrobić przerwę, naciśnij [orange]spację[] lub [orange]przycisk pauzy[] w lewym górnym rogu. Nadal możesz wybierać i wstawiać klocki podczas pauzy, ale nie możesz niszczyć i strzelać. -tutorial.pausingAndroid.text = Jeśli chcesz zrobić przerwę, naciśnij [orange]przycisk pauzy[]. Nadal możesz stawiać i niszczyć bloki. -tutorial.purchaseWeapons.text = Możesz kupić nowe [żółte] bronie [] dla swojego mecha, otwierając menu aktualizacji w lewym dolnym rogu. -tutorial.switchWeapons.text = Zmień broń, klikając jej ikonę w lewym dolnym rogu lub używając cyfr [orange][1-9[]. -tutorial.spawnWave.text = Fala wrogów nadchodzi! Zniszcz ich. -tutorial.pumpDesc.text = W późniejszych falach może być konieczne użycie [yellow]pompy[] do rozprowadzania cieczy dla generatorów lub ekstraktorów. -tutorial.pumpPlace.text = Pompy działają podobnie do wierteł, z tym wyjątkiem, że wytwarzają ciecze zamiast ród.\nSpróbuj umieścić pompę na [yellow]oleju[]. -tutorial.conduitUse.text = Teraz umieść [orange]rurę[] wychodzącą od pompy. -tutorial.conduitUse2.text = I tak jeszcze jedną... -tutorial.conduitUse3.text = I jeszcze jedeną... -tutorial.generator.text = Teraz umieść [orange]generator spalinowy[] na końcu kanału. -tutorial.generatorExplain.text = Generator ten będzie teraz wytwarzać [yellow]energię[] z oleju. -tutorial.lasers.text = Energia jest dystrybuowana za pomocą [yellow]przekaźników[]. Umieść takowy przekaźnik na [yellow]wskazanej pozycji[]. -tutorial.laserExplain.text = Generator przeniesie teraz moc do przekaźnika. Wiązka [orange]nieprzeźroczysta[] oznacza, że ​​aktualnie transmituje moc. Wiązka [yellow]przeźroczysta[] wskazuje na brak przekazywanej energii. -tutorial.laserMore.text = Możesz sprawdzić ile energii przechowuje blok najeżdżając na niego kursorem i sprawdzając [yellow]żółty pasek[]. -tutorial.healingTurret.text = Energia może być używany do zasilania [lime]wież naprawczych[]. Umieść takową [yellow]tutaj[]. -tutorial.healingTurretExplain.text = Dopóki dostarczana jest do niej energia będzie [lime]naprawiać pobliskie bloki[]. Podczas gry ustawiłeś ją niedaleko swojej bazy tak szybko, jak to tylko możliwe! -tutorial.smeltery.text = Wiele bloków wymaga do pracy [orange]stali[], którą można wytwarzać w [orange]hucie[]. A skoro tak, to postaw ją teraz. -tutorial.smelterySetup.text = Huta wytworzy teraz z żelaza [orange]stal[], wykorzystując węgiel jako paliwo. -tutorial.tunnelExplain.text = Zwróć też uwagę, że przedmioty przechodzą przez [orange]tunel[] i wynurzają się po drugiej stronie, przechodząc przez kamienny blok. Pamiętaj, że tunele mogą przechodzić tylko do 2 bloków. -tutorial.end.text = I na tym poradnik się kończy!\nPozostaje tylko życzyć Ci [orange]powodzenia[]! -keybind.move_x.name = Poruszanie w poziomie -keybind.move_y.name = Poruszanie w pionie -keybind.select.name = Wybieranie -keybind.break.name = Niszczenie -keybind.shoot.name = Strzelanie -keybind.zoom_hold.name = Inicjator przybliżania -keybind.zoom.name = Przybliżanie -keybind.menu.name = menu -keybind.pause.name = pauza -keybind.dash.name = przyśpieszenie -keybind.rotate_alt.name = Obracanie (1) -keybind.rotate.name = Obracanie (2) -keybind.weapon_1.name = Broń 1 -keybind.weapon_2.name = Broń 2 -keybind.weapon_3.name = Broń 3 -keybind.weapon_4.name = Broń 4 -keybind.weapon_5.name = Broń 5 -keybind.weapon_6.name = Broń 6 -mode.waves.name = Fale -mode.sandbox.name = sandbox -mode.freebuild.name = budowanie -upgrade.standard.name = Standardowy -upgrade.standard.description = Standardowy mech. -upgrade.blaster.name = blaster -upgrade.blaster.description = Wystrzeliwuje powolną, słabą kulę. -upgrade.triblaster.name = triblaster -upgrade.triblaster.description = Strzela 3 pociskami w rozprzestrzenianiu. -upgrade.clustergun.name = clustergun -upgrade.clustergun.description = Wystrzeliwuje w różnych kierunkach kilka granatów. -upgrade.beam.name = Działko laserowe -upgrade.beam.description = Strzela laserem o dalekim zasięgu. -upgrade.vulcan.name = wulkan -upgrade.vulcan.description = Wystrzeliwuje grad szybkich pocisków. -upgrade.shockgun.name = Działko elektryczne -upgrade.shockgun.description = Wystrzeliwuje niszczycielski podmuch naładowanych odłamków. -item.stone.name = kamień -item.iron.name = żelazo -item.coal.name = węgiel -item.steel.name = stal -item.titanium.name = tytan -item.dirium.name = dirium -item.thorium.name = uran -item.sand.name = piasek -liquid.water.name = woda -liquid.plasma.name = plazma -liquid.lava.name = lawa -liquid.oil.name = olej -block.weaponfactory.name = fabryka broni -block.air.name = Powietrze. -block.blockpart.name = Kawałek bloku -block.deepwater.name = głęboka woda -block.water.name = woda -block.lava.name = lawa -block.oil.name = olej -block.stone.name = kamień -block.blackstone.name = czarny kamień -block.iron.name = żelazo -block.coal.name = węgiel -block.titanium.name = tytan -block.thorium.name = uran -block.dirt.name = ziemia -block.sand.name = piasek -block.ice.name = lód -block.snow.name = śnieg -block.grass.name = trawa -block.sandblock.name = blok z piasku -block.snowblock.name = blok ze śniegu -block.stoneblock.name = blok z kamienia -block.blackstoneblock.name = blok z czarnego kamienia -block.grassblock.name = blok z trawy -block.mossblock.name = porośnięty blok -block.shrub.name = krzew -block.rock.name = kamyk -block.icerock.name = kamyk lodowy -block.blackrock.name = czarny kamyk -block.dirtblock.name = Brudny blok -block.stonewall.name = Kamienna ściana -block.stonewall.fulldescription = Tani blok obronny. Przydatny do ochrony rdzenia i wież w pierwszych kilku falach. -block.ironwall.name = Żelazna ściana -block.ironwall.fulldescription = Podstawowy blok obronny. Zapewnia ochronę przed wrogami. -block.steelwall.name = stalowa ściana -block.steelwall.fulldescription = Standardowy blok obronny. odpowiednia ochrona przed wrogami. -block.titaniumwall.name = tytanowa ściana -block.titaniumwall.fulldescription = Silny blok obronny. Zapewnia ochronę przed wrogami. -block.duriumwall.name = ściana z dirium -block.duriumwall.fulldescription = Bardzo silny blok obronny. Zapewnia ochronę przed wrogami. -block.compositewall.name = ściana kompozytowa -block.steelwall-large.name = duża stalowa ściana -block.steelwall-large.fulldescription = Standardowy blok obronny. Rozpiętość wielu płytek. -block.titaniumwall-large.name = duża tytanowa ściana -block.titaniumwall-large.fulldescription = Silny blok obronny. Rozpiętość wielu płytek. -block.duriumwall-large.name = duża ściana z dirium -block.duriumwall-large.fulldescription = Bardzo silny blok obronny. Rozpiętość wielu płytek. -block.titaniumshieldwall.name = Ściana z polem obronnym -block.titaniumshieldwall.fulldescription = Silny blok obronny z dodatkową wbudowaną tarczą. Wymaga zasilania. Używa energii do pochłaniania pocisków wroga. W celu dostarczenia zasilania zaleca się stosowanie wzmacniaczy energii. -block.repairturret.name = Wieża naprawcza -block.repairturret.fulldescription = Naprawia pobliskie uszkodzone bloki w niedużej prędkości. Wykorzystuje niewielkie ilości energii. -block.megarepairturret.name = Wieża naprawcza II -block.megarepairturret.fulldescription = Naprawia pobliskie uszkodzone bloki z przyzwoitą prędkośą. Do działania wykorzystuje energię. -block.shieldgenerator.name = Generator tarczy -block.shieldgenerator.fulldescription = Zaawansowany blok obronny. Osłania wszystkie bloki w promieniu przed atakiem wroga. Zużywa energię z niewielką prędkością gdy jest w stanie bezczynności, ale z kolei gdy jest w użyciu, energię pobiera bardzo szybko. -block.door.name = drzwi -block.door.fulldescription = Blok, który można otworzyć i zamknąć poprzez dotknięcie -block.door-large.name = duże drzwi -block.door-large.fulldescription = Blok, który można otworzyć i zamknąć poprzez dotknięcie -block.conduit.name = Rura -block.conduit.fulldescription = Podstawowy blok transportu cieczy. Działa jak przenośnik, tylko że z płynami. Najlepiej stosować z pompami bądź razem innymi rurami.\nMoże być używany jako pomost nad płynami dla wrogów i graczy. -block.pulseconduit.name = Rura impulsowa -block.pulseconduit.fulldescription = Zaawansowany blok transportu cieczy. Transportuje ciecze szybciej i przechowuje więcej niż rury standardowe. -block.liquidrouter.name = Rozdzielacz płynów -block.liquidrouter.fulldescription = Działa podobnie do zwykłego rozdzielacza. Akceptuje wejście cieczy z jednej strony i przekazuje ją na pozostałe strony. Przydatny do rozdzielania cieczy z jednej rury do wielu. -block.conveyor.name = Przenośnik -block.conveyor.fulldescription = Podstawowy blok transportu przedmiotów. Przenosi przedmioty do przodu i automatycznie umieszcza je w blokach. Może być używany jako pomost nad płynami dla wrogów i graczy. -block.steelconveyor.name = Przenośnik stalowy -block.steelconveyor.fulldescription = Zaawansowany blok transportu przedmiotów. Przenosi elementy szybciej niż standardowe przenośniki. -block.poweredconveyor.name = przenośnik impulsowy -block.poweredconveyor.fulldescription = Najszybszy blok transportowy przedmiotów. -block.router.name = Rozdzielacz -block.router.fulldescription = Przyjmuje przedmioty z jednego kierunku i przekazuje je w 3 innych kierunkach. Może również przechowywać pewną liczbę przedmiotów. Przydatny do dzielenia materiałów z jednego wiertła na wiele dział. -block.junction.name = węzeł -block.junction.fulldescription = Działa jako pomost dla dwóch skrzyżowanych przenośników taśmowych. Przydatny w sytuacjach, gdy dwa różne przenośniki przenoszą różne materiały do ​​różnych lokalizacji. -block.conveyortunnel.name = tunel przenośnikowy -block.conveyortunnel.fulldescription = Transportuje przedmiot pod blokami. Aby użyć, umieść jeden tunel prowadzący do bloku, który ma zostać tunelowany, i jeden po drugiej stronie. Upewnij się, że oba tunele są skierowane w przeciwnych kierunkach, czyli w wejście do bloku podającego, a wyjście do bloku odbierającego. -block.liquidjunction.name = Węzeł dla płynów -block.liquidjunction.fulldescription = Skrzyżowanie dla rurociągów. Przydatne w sytuacji, w której transportujemy różne ciecze w rurach, które muszą się przeciąć. -block.liquiditemjunction.name = Węzeł rur i przenośników -block.liquiditemjunction.fulldescription = Skrzyżowanie przenośników taśmowych oraz rur. -block.powerbooster.name = Wzmacniacz energii -block.powerbooster.fulldescription = Dystrybuuje moc do wszystkich bloków w swoim promieniu. -block.powerlaser.name = Przekaźnik -block.powerlaser.fulldescription = Tworzy laser, który przesyła moc do bloku przed nim. Nie generuje energii. Najlepiej stosować z generatorami lub innymi przekaźnikami. -block.powerlaserrouter.name = Duży rozdzielacz energii -block.powerlaserrouter.fulldescription = Przekaźnik, który dystrybuuje energię w trzech kierunkach jednocześnie. Przydatne w sytuacjach, w których wymagane jest zasilanie wielu bloków z jednego generatora. -block.powerlasercorner.name = Rozdzielacz energii -block.powerlasercorner.fulldescription = Przekaźnik, który dystrybuuje energię w dwóch kierunkach jednocześnie. Przydatny w sytuacjach, gdy wymagane jest zasilanie wielu bloków z jednego generatora, a router jest nieprecyzyjny. -block.teleporter.name = teleporter -block.teleporter.fulldescription = Zaawansowany blok transportu przedmiotów. Teleporty przenoszą przedmioty do innych teleportów tego samego koloru. Jeżeli nie istnieją teleporty z tym samym kolorem, to nie niczego nigdzie nie przenosi. Jeśli istnieje wiele teleportów tego samego koloru, wybierany jest losowy. Zużywa energię. Stuknij aby zmienić kolor. -block.sorter.name = Sortownik -block.sorter.fulldescription = Sortuje przedmioty według rodzaju materiału. Materiał do zaakceptowania jest oznaczony w bloku. Wszystkie pasujące przedmioty są wysyłane do przodu, wszystko inne jest wyprowadzane na lewo i na prawo. -block.core.name = Rdzeń -block.pump.name = pompa -block.pump.fulldescription = Pompuje ciecze z bloku źródłowego - zwykle wody, lawy lub oleju. Wyprowadza ciecz do pobliskich rur. -block.fluxpump.name = pompa strumieniowa -block.fluxpump.fulldescription = Zaawansowana wersja pompy. Przechowuje więcej cieczy i szybciej pompuje. -block.smelter.name = huta -block.smelter.fulldescription = Niezbędny blok rzemieślniczy. Po wprowadzeniu 1 żelaza i 1 węgla jako paliwa, wytwarza 1 stal. Zaleca się wprowadzanie żelaza i węgla na różne pasy, aby zapobiec zatkaniu. -block.crucible.name = tygiel -block.crucible.fulldescription = Zaawansowany blok rzemieślniczy. Po wprowadzeniu 1 tytanu, 1 stali i 1 węgla jako paliwa, otrzymuje 1 dirium. Zaleca się wprowadzanie węgla, stali i tytanu z różnych taśm, aby zapobiec zatkaniu. -block.coalpurifier.name = ekstraktor węgla -block.coalpurifier.fulldescription = Wyprowadza węgiel, gdy jest dostarczana duża ilością wody i kamienia. -block.titaniumpurifier.name = ekstraktor tytanu -block.titaniumpurifier.fulldescription = Wyprowadza tytan, gdy jest dostarczana duża ilości wody i żelaza. -block.oilrefinery.name = Rafineria ropy -block.oilrefinery.fulldescription = Rafinuje duże ilości oleju do postaci węgla. Przydatne do napędzania działek napędzanych węglem, gry nie ma w pobliżu wystarcząjacej ilości rud węgla. -block.stoneformer.name = Wytwarzacz kamienia -block.stoneformer.fulldescription = Schładza lawę do postaci kamień. Przydatny do produkcji ogromnych ilości kamienia do oczyszczania węgla. -block.lavasmelter.name = Huta lawowa -block.lavasmelter.fulldescription = Używa lawy, by przekształcić żelazo w stal. Alternatywa dla zwykłych hut. Przydatny w sytuacjach, gdy brakuje węgla. -block.stonedrill.name = wiertło do kamienia -block.stonedrill.fulldescription = Niezbędne wiertło. Po umieszczeniu na kamiennym podłożu, powoli i w nieskończoność wydobywa kamień. -block.irondrill.name = wiertło do żelaza -block.irondrill.fulldescription = Po umieszczeniu na rudzie żelaza, powoli i w nieskończoność wydobywa żelazo. -block.coaldrill.name = wiertło do węgla -block.coaldrill.fulldescription = Po umieszczeniu na rudzie węgla, powoli i w nieskończoność wydobywa węgiel. -block.thoriumdrill.name = wiertło do uranu -block.thoriumdrill.fulldescription = Wiertło zaawansowane. Po umieszczeniu na rudzie uranu, wydobywa uran w wolnym tempie przez czas nieokreślony. -block.titaniumdrill.name = wiertło do tytanu -block.titaniumdrill.fulldescription = Wiertło zaawansowane. Po umieszczeniu na rudzie tytanu, wydobywa tytan w wolnym tempie przez czas nieokreślony. -block.omnidrill.name = omnidril -block.omnidrill.fulldescription = Wiertło wielofunkcyjne. W szybkim tempie wydobywa każdą rudę. -block.coalgenerator.name = generator na węgiel -block.coalgenerator.fulldescription = Niezbędny generator. Generuje energię z węgla na wszystkie strony. -block.thermalgenerator.name = generator termiczny -block.thermalgenerator.fulldescription = Generuje energię z lawy. Generuje energię z węgla na wszystkie strony. -block.combustiongenerator.name = generator spalinowy -block.combustiongenerator.fulldescription = Generuje moc z oleju. Generuje energię z węgla na wszystkie strony. -block.rtgenerator.name = Generator RTG -block.rtgenerator.fulldescription = Generuje niewielkie ilości energii z rozpadu promieniotwórczego uranu. Generuje energię z węgla na wszystkie strony. -block.nuclearreactor.name = reaktor jądrowy -block.nuclearreactor.fulldescription = Zaawansowana wersja generatora RTG i zarazem najlepsze źródło energii. Generuje ją z uranu. Wymaga stałego chłodzenia wodą. Wybucha niemal natychmiast w momencie, gdy dostarczona zostanie niewystarczająca ilość płynu chłodzącego. -block.turret.name = działko -block.turret.fulldescription = Podstawowa, nieduża wieżyczka. Używa kamienia jako amunicji. Ma nieco większy zasięg niż działko podwójne. -block.doubleturret.name = działko podwójne -block.doubleturret.fulldescription = Nieco mocniejsza wersja działka. Używa kamienia jako amunicji. Znacznie więcej obrażeń, ale ma mniejszy zasięg. Wystrzeliwuje dwie kule. -block.machineturret.name = działko szybkostrzelne -block.machineturret.fulldescription = Standardowa, wszechstronna wieża. Używa żelaza jako amunicji. Strzela dość szybko i ma przyzwoite uszkodzenia. -block.shotgunturret.name = działko odłamkowe -block.shotgunturret.fulldescription = Standardowa wieża. Używa żelaza do amunicji. Wystrzeliwuje 7 pocisków. Niższy zasięg, ale większe obrażenia niż działko szybkostrzelne. -block.flameturret.name = miotacz ognia -block.flameturret.fulldescription = Zaawansowana wieżyczka bliskiego zasięgu. Używa węgla jako amunicji. Ma bardzo niski zasięg, ale bardzo duże obrażenia. Dobra na krótkie dystanse. Zalecana do stosowania za ścianami. -block.sniperturret.name = karabin -block.sniperturret.fulldescription = Zaawansowana wieżyczka dalekiego zasięgu. Używa stali jako amunicji. Ma bardzo duże obrażenia, ale niski współczynnik ognia. Kosztowne w użyciu, ale można je umieścić z dala od linii wroga ze względu na jego zasięg. -block.mortarturret.name = Miotacz odłamków -block.mortarturret.fulldescription = Zaawansowana, bardzo dokładne działko rozpryskowe. Używa węgla jako amunicji. Wystrzeliwuje grad eksplodujących pocisków. Przydatny dla dużych hord wrogów. -block.laserturret.name = działo laserowe -block.laserturret.fulldescription = Zaawansowana wieża z jednym celem. Używa energii. Dobra wieża o średnim zasięgu. Atakuje tylko 1 cel i nigdy nie pudłuje. -block.waveturret.name = Działo Tesli -block.waveturret.fulldescription = Zaawansowana wieża celującai. Używa mocy. Średni zasięg. Nigdy nie trafia. Stosuje niskie obrażenia, ale może trafić wielu wrogów jednocześnie z oświetleniem łańcuszkiem. -block.plasmaturret.name = Działo plazmowe -block.plasmaturret.fulldescription = Wysoce zaawansowana wersja miotacza ognia. Używa węgla jako amunicji. Zadaje bardzo duże obrażenia i posiada średni zasięg. -block.chainturret.name = Działo uranowe -block.chainturret.fulldescription = Najlepsze działo szybkiego ognia. Używa uranu jako amunicji. Wystrzeliwuje duże spirale z dużą szybkością. Posiada średni zasięg. -block.titancannon.name = Potężne działo uranowe -block.titancannon.fulldescription = Najlepsze działo dalekiego zasięgu. Używa uranu jako amunicji. Wystrzeliwuje duże pociski z odłamkami. Ma średnią szybkostrzelność i duży promień rażenia. -block.playerspawn.name = Spawn gracza -block.enemyspawn.name = Spawn wroga +text.about=Stworzony przez [ROYAL] Anuken. []\nPierwotnie wpis w [orange] GDL [] MM Jam.\n\nNapisy:\n- SFX wykonane z pomocą [YELLOW] bfxr []\n- Muzyka wykonana przez [GREEN] RoccoW [] / znaleziona na [lime] FreeMusicArchive.org []\n\nSpecjalne podziękowania dla:\n- [coral] MitchellFJN []: obszerne testowanie i feedback\n- [niebo] Luxray5474 []: prace związane z wiki, pomoc z kodem\n- Wszystkich beta testerów na itch.io i Google Play\n +text.discord=Odwiedź nasz serwer Discord +text.gameover=Rdzeń został zniszczony. +text.highscore=[YELLOW] Nowy rekord! +text.lasted=Wytrwałeś do fali +text.level.highscore=Rekord: [accent]{0} +text.level.delete.title=Potwierdź kasowanie +text.level.select=Wybrany poziom +text.level.mode=Tryb gry: +text.savegame=Zapisz Grę +text.loadgame=Wczytaj grę +text.joingame=Gra wieloosobowa +text.quit=Wyjdź +text.about.button=O grze +text.name=Nazwa: +text.players={0} graczy online +text.players.single={0} gracz online +text.server.mismatch=Błąd pakietu: możliwa niezgodność wersji klienta/serwera.\nUpewnij się, że Ty i host macie najnowszą wersję Mindustry! +text.server.closing=[accent] Zamykanie serwera ... +text.server.kicked.kick=Zostałeś wyrzucony z serwera! +text.server.kicked.invalidPassword=Nieprawidłowe hasło! +text.server.kicked.clientOutdated=Nieaktualna gra! Zaktualizują ją! +text.server.kicked.serverOutdated=Nieaktualna gra! Zaktualizują ją! +text.server.connected={0} dołączył do gry . +text.server.disconnected={0} został rozłączony. +text.nohost=Nie można hostować serwera na mapie niestandardowej! +text.hostserver=Serwer hosta +text.host=Host +text.hosting=[accent] Otwieranie serwera ... +text.hosts.refresh=Odśwież +text.hosts.discovering=Wyszukiwanie gier w sieci LAN +text.server.refreshing=Odświeżanie serwera +text.hosts.none=[lightgray] Brak serwerów w sieci LAN! +text.host.invalid=[scarlet] Nie można połączyć się z hostem. +text.server.friendlyfire=Bratobójczy ogień +text.server.add=Dodaj serwer +text.server.delete=Czy na pewno chcesz usunąć ten serwer? +text.server.hostname=Host: {0} +text.server.edit=Edytuj serwer +text.joingame.title=Dołącz do gry +text.joingame.ip=IP: +text.disconnect=Rozłączony. +text.connecting=[accent]Łączenie ... +text.connecting.data=[accent]Ładowanie danych świata... +text.connectfail=[crimson]Nie można połączyć się z serwerem: [orange] {0} +text.server.port=Port: +text.server.addressinuse=Adres jest już w użyciu! +text.server.invalidport=Nieprawidłowy numer portu. +text.server.error=[crimson] Błąd hostowania serwera: [orange] {0} +text.save.new=Nowy zapis +text.save.overwrite=Czy na pewno chcesz nadpisać zapis gry? +text.overwrite=Nadpisz +text.save.none=Nie znaleziono zapisów gry! +text.saveload=[akcent]Zapisywanie... +text.savefail=Nie udało się zapisać gry! +text.save.delete.confirm=Czy na pewno chcesz usunąć ten zapis gry? +text.save.delete=Usuń +text.save.export=Eksportuj +text.save.import.invalid=[orange]Zapis gry jest niepoprawny! +text.save.import.fail=[crimson]Nie udało się zaimportować zapisu: [orange] {0} +text.save.export.fail=[crimson]Nie można wyeksportować zapisu: [orange] {0} +text.save.import=Importuj +text.save.newslot=Zapisz nazwę: +text.save.rename=Zmień nazwę +text.save.rename.text=Zmień nazwę +text.selectslot=Wybierz zapis. +text.slot=[accent]Slot {0} +text.save.corrupted=[orange]Zapis gry jest uszkodzony lub nieprawidłowy! +text.empty= +text.on=Włączone +text.off=Wyłączone +text.save.autosave=Zapisywanie automatyczne +text.save.map=Mapa: {0} +text.save.wave=Fala: {0} +text.save.date=Ostatnio zapisano: {0} +text.confirm=Potwierdź +text.delete=Usuń +text.ok=Ok +text.open=Otwórz +text.cancel=Anuluj +text.openlink=Otwórz link +text.back=Wróć +text.quit.confirm=Czy na pewno chcesz wyjść? +text.loading=[accent]Ładowanie ... +text.wave=[orange]Fala {0} +text.wave.waiting=Fala w {0} +text.waiting=Oczekiwanie... +text.enemies={0} wrogów +text.enemies.single={0} wróg +text.loadimage=Załaduj obraz +text.saveimage=Zapisz obraz +text.editor.badsize=[orange]Nieprawidłowe wymiary obrazu![]\nWymiary poprawne: {0} +text.editor.errorimageload=Błąd podczas ładowania pliku obrazu: [orange]{0} +text.editor.errorimagesave=Błąd podczas zapisywania pliku obrazu: [orange]{0} +text.editor.generate=Generuj +text.editor.resize=Zmień rozmiar +text.editor.loadmap=Załaduj mapę +text.editor.savemap=Zapisz mapę +text.editor.loadimage=Załaduj obraz +text.editor.saveimage=Zapisz obraz +text.editor.unsaved=[scarlet]Masz niezapisane zmiany![]\nCzy na pewno chcesz wyjść? +text.editor.resizemap=Zmień rozmiar mapy +text.editor.mapname=Nazwa mapy: +text.editor.overwrite=[accent]Uwaga!\nSpowoduje to nadpisanie istniejącej mapy. +text.editor.selectmap=Wybierz mapę do załadowania: +text.width=Szerokość: +text.height=Wysokość: +text.menu=Menu +text.play=Graj +text.load=Wczytaj +text.save=Zapisz +text.language.restart=Uruchom grę ponownie aby ustawiony język zaczął funkcjonować. +text.settings.language=Język +text.settings=Ustawienia +text.tutorial=Poradnik +text.editor=Edytor +text.mapeditor=Edytor map +text.donate=Wspomóż nas +text.settings.reset=Przywróć domyślne +text.settings.controls=Sterowanie +text.settings.game=Gra +text.settings.sound=Dźwięk +text.settings.graphics=Grafika +text.upgrades=Ulepszenia +text.purchased=[LIME]Stworzono! +text.weapons=Bronie +text.paused=Wstrzymano +text.info.title=[accent]Informacje +text.error.title=[crimson]Wystąpił błąd +text.error.crashtitle=Wystąpił błąd +text.blocks.blockinfo=Informacje o bloku +text.blocks.powercapacity=Moc znamionowa +text.blocks.powershot=moc / strzał +text.blocks.size=Rozmiar +text.blocks.liquidcapacity=Pojemność cieczy +text.blocks.maxitemssecond=Maksymalna liczba przedmiotów / Sekunda +text.blocks.powerrange=Zakres mocy +text.blocks.itemcapacity=Pojemność przedmiotów +text.blocks.inputliquid=Potrzebna ciecz +text.blocks.inputitem=Potrzebne przedmioty +text.blocks.explosive=Wysoce wybuchowy! +text.blocks.health=Zdrowie +text.blocks.inaccuracy=Niedokładność +text.blocks.shots=Strzały +text.blocks.inputcapacity=Pojemność wejściowa +text.blocks.outputcapacity=Wydajność wyjściowa +setting.difficulty.easy=łatwy +setting.difficulty.normal=normalny +setting.difficulty.hard=trudny +setting.difficulty.insane=szalony +setting.difficulty.purge=Czystka +setting.difficulty.name=Poziom trudności +setting.screenshake.name=Trzęsienie się ekranu +setting.indicators.name=Wskaźniki wroga +setting.effects.name=Wyświetlanie efektów +setting.sensitivity.name=Czułość kontrolera +setting.saveinterval.name=Interwał automatycznego zapisywania +setting.seconds=Sekundy +setting.fps.name=Widoczny licznik FPS +setting.vsync.name=Synchronizacja pionowa +setting.lasers.name=Pokaż lasery zasilające +setting.healthbars.name=Pokaż paski zdrowia jednostki +setting.musicvol.name=Głośność muzyki +setting.mutemusic.name=Wycisz muzykę +setting.sfxvol.name=Głośność dźwięków +setting.mutesound.name=Wycisz dźwięki +map.maze.name=labirynt +map.fortress.name=twierdza +map.sinkhole.name=wgłębienie +map.caves.name=jaskinie +map.volcano.name=wulkan +map.caldera.name=kaldera +map.scorch.name=opalacz +map.desert.name=pustynia +map.island.name=wyspa +map.grassland.name=łąka +map.tundra.name=tundra +map.spiral.name=spirala +map.tutorial.name=Poradnik +keybind.move_x.name=Poruszanie w poziomie +keybind.move_y.name=Poruszanie w pionie +keybind.select.name=Wybieranie +keybind.break.name=Niszczenie +keybind.shoot.name=Strzelanie +keybind.zoom_hold.name=Inicjator przybliżania +keybind.zoom.name=Przybliżanie +keybind.menu.name=menu +keybind.pause.name=pauza +keybind.dash.name=przyśpieszenie +keybind.rotate_alt.name=Obracanie (1) +keybind.rotate.name=Obracanie (2) +mode.waves.name=Fale +mode.sandbox.name=sandbox +mode.freebuild.name=budowanie +item.stone.name=kamień +item.coal.name=węgiel +item.titanium.name=tytan +item.thorium.name=uran +item.sand.name=piasek +liquid.water.name=woda +liquid.lava.name=lawa +liquid.oil.name=olej +block.door.name=drzwi +block.door-large.name=duże drzwi +block.conduit.name=Rura +block.pulseconduit.name=Rura impulsowa +block.liquidrouter.name=Rozdzielacz płynów +block.conveyor.name=Przenośnik +block.router.name=Rozdzielacz +block.junction.name=węzeł +block.liquidjunction.name=Węzeł dla płynów +block.sorter.name=Sortownik +block.smelter.name=huta +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.newgame=New Game +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.banned=You are banned on this server. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.trace=Trace Player +text.trace.playername=Player name: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Unique ID: [accent]{0} +text.trace.android=Android Client: [accent]{0} +text.trace.modclient=Custom Client: [accent]{0} +text.trace.totalblocksbroken=Total blocks broken: [accent]{0} +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.trace.lastblockbroken=Last block broken: [accent]{0} +text.trace.totalblocksplaced=Total blocks placed: [accent]{0} +text.trace.lastblockplaced=Last block placed: [accent]{0} +text.invalidid=Invalid client ID! Submit a bug report. +text.server.bans=Bans +text.server.bans.none=No banned players found! +text.server.admins=Admins +text.server.admins.none=No admins found! +text.server.outdated=[crimson]Outdated Server![] +text.server.outdated.client=[crimson]Outdated Client![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[yellow]Custom Build +text.confirmban=Are you sure you want to ban this player? +text.confirmunban=Are you sure you want to unban this player? +text.confirmadmin=Are you sure you want to make this player an admin? +text.confirmunadmin=Are you sure you want to remove admin status from this player? +text.disconnect.data=Failed to load world data! +text.save.difficulty=Difficulty: {0} +text.copylink=Copy Link +text.changelog.title=Changelog +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.fullscreen.name=Fullscreen +setting.multithread.name=Multithreading +setting.minimap.name=Show Minimap +text.keybind.title=Rebind Keys +keybind.block_info.name=block_info +keybind.chat.name=chat +keybind.player_list.name=player_list +keybind.console.name=console +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index f4fd7b0cee..3b54e1282d 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -3,9 +3,8 @@ text.discord=Junte-se ao Discord do Mindustry! (Lá nós falamos em inglês) text.gameover=O núcleo foi destruído. text.highscore=[YELLOW]Novo recorde! text.lasted=Você durou até a horda -text.level.highscore= Melhor\npontuação: [accent] {0} +text.level.highscore=Melhor\npontuação: [accent] {0} text.level.delete.title=Confirmar exclusão -text.level.delete=Você tem certeza que quer excluir\no mapa "[orange]{0}"? text.level.select=Seleção de Fase text.level.mode=Modo de Jogo: text.savegame=Salvar Jogo @@ -33,7 +32,6 @@ text.loading=[accent]Carregando... text.wave=[orange]Horda {0} text.wave.waiting=Horda em {0} text.waiting=Aguardando... -text.countdown=Horda em {0} text.enemies={0} Inimigos restantes text.enemies.single={0} Inimigo restante text.loadimage=Carregar\nImagem @@ -48,21 +46,12 @@ text.editor.savemap=Salvar\n Mapa text.editor.loadimage=Carregar\n Imagem text.editor.saveimage=Salvar\nImagem text.editor.unsaved=[scarlet]Você tem alterações não salvas![]\nTem certeza que quer sair? -text.editor.brushsize=Tamanho do pincel: {0} -text.editor.noplayerspawn=Este mapa não tem ponto de spawn para o jogador! -text.editor.manyplayerspawns=Mapas não podem ter mais de um\nponto de spawn para jogador! -text.editor.manyenemyspawns=Não pode haver mais de\n{0} pontos de spawn para inimigos! text.editor.resizemap=Redimensionar Mapa -text.editor.resizebig=[scarlet]Aviso!\n[]Mapas maiores que 256 unidades podem ser 'lentos' e instáveis text.editor.mapname=Nome do Mapa: text.editor.overwrite=[accent]Aviso!\nIsso sobrescreve um mapa existente. -text.editor.failoverwrite=[crimson]Não é possível salvar sobre o mapa padrão! text.editor.selectmap=Selecione uma mapa para carregar: text.width=Largura: text.height=Altura: -text.randomize=Aleatório -text.apply=Aplicar -text.update=Atualizar text.menu=Menu text.play=Jogar text.load=Carregar @@ -81,58 +70,27 @@ text.upgrades=Melhorias text.purchased=[LIME]Comprado! text.weapons=Arsenal text.paused=Pausado -text.respawn=Reaparecendo em text.error.title=[crimson]Um erro ocorreu -text.error.crashmessage=[SCARLET]Um erro inesperado aconteceu, que pode ter causado o jogo a fechar. []Por favor, informe as exatas circunstâncias em que o erro ocorreu ao desenvolvidor:\n[ORANGE]anukendev@gmail.com[] text.error.crashtitle=Um erro ocorreu. -text.blocks.extrainfo=[accent]Informação extra: text.blocks.blockinfo=Informação do Bloco text.blocks.powercapacity=Capacidade de Energia text.blocks.powershot=Energia/tiro -text.blocks.powersecond=Energia/segundo -text.blocks.powerdraindamage=Energia/dano -text.blocks.shieldradius=Raio do Escudo -text.blocks.itemspeedsecond=Itens/segundo -text.blocks.range=Alcance text.blocks.size=Tamanho -text.blocks.powerliquid=Energia/Líquido -text.blocks.maxliquidsecond=Entrada Máx. Líquido/segundo text.blocks.liquidcapacity=Capacidade de Líquido -text.blocks.liquidsecond=Líquido/segundo -text.blocks.damageshot=Dano/tiro -text.blocks.ammocapacity=Munição Máxima -text.blocks.ammo=Munição -text.blocks.ammoitem=Munição/item text.blocks.maxitemssecond=Máximo de itens/segundo text.blocks.powerrange=Alcance da Energia -text.blocks.lasertilerange=Alcance do Laser (em células) -text.blocks.capacity=Capacidade text.blocks.itemcapacity=Capacidade de Itens -text.blocks.powergenerationsecond=Geração de Energia/segundo -text.blocks.generationsecondsitem=Tempo de geração/item -text.blocks.input=Entrada text.blocks.inputliquid=Líquido de entrada text.blocks.inputitem=Item de entrada -text.blocks.output=Saída -text.blocks.secondsitem=Segundos/item -text.blocks.maxpowertransfersecond=Transferência máxima de Energia/segundo text.blocks.explosive=Altamente Explosivo! -text.blocks.repairssecond=Reparo/segundo text.blocks.health=Saúde text.blocks.inaccuracy=Imprecisão text.blocks.shots=Tiros -text.blocks.shotssecond=Taxa de tiro -text.placemode=Modo construção -text.breakmode=Modo remoção -text.health=Saúde setting.difficulty.easy=Fácil setting.difficulty.normal=Normal setting.difficulty.hard=Difícil setting.difficulty.name=Dificuldade setting.screenshake.name=Balanço da Tela -#Tremor da tela? -setting.smoothcam.name=Câmera suave -#Suavizar Câmera? setting.indicators.name=Indicadores de Inimigos setting.effects.name=Particulas setting.sensitivity.name=Sensibilidade do Controle @@ -140,7 +98,6 @@ setting.fps.name=Mostrar FPS setting.vsync.name=VSync setting.lasers.name=Mostrar lasers setting.healthbars.name=Mostrar barra de saúde de entidades -setting.pixelate.name=Pixelar Tela setting.musicvol.name=Volume da Música setting.mutemusic.name=Desligar Musica setting.sfxvol.name=Volume de Efeitos @@ -158,54 +115,10 @@ map.grassland.name=grassland map.tundra.name=tundra map.spiral.name=spiral map.tutorial.name=tutorial -tutorial.intro.text=[yellow]Bem-vindo ao tutorial.[] Para começar aperte 'próximo'. -tutorial.moveDesktop.text=Para mover, use as teclas [orange][[WASD][]. Segure [orange]shift[] para mover rápido. Segure [orange]CTRL[] enquanto usa a [orange]roda do mouse[] para aumentar ou diminuir o zoom. -tutorial.shootInternal.text=Use o mouse para mirar, segure [orange]botão esquerdo do mouse[] para atirar. Tente praticar no [yellow]alvo[]. -tutorial.moveAndroid.text=Para arrastar a visão, passe um dedo pela tela. Pince com os dedos para aumentar ou diminuir o zoom. -tutorial.placeSelect.text=Tente selecionar uma [yellow]esteira[] do menu de blocos no canto inferior direito. -tutorial.placeConveyorDesktop.text=Use a [orange][[roda do mouse][] para girar a esteira até que aponte [orange]para frente[], então coloque-a no [yellow]local marcado[] usando o [orange][[botão esquerdo do mouse][]. -tutorial.placeConveyorAndroid.text=Use o [orange][[botão de girar][] para girar a esteira para que aponte [orange]para frente[], arraste-a para a posição e então coloque-a na [yellow]posição marcada[] usando o [orange][[botão de confirmação][]. -tutorial.placeConveyorAndroidInfo.text=Você também pode apertar no ícone com uma cruz no canto inferior esquerdo para alterar para o [orange][[modo de toque][], e colocar blocos apertando na tela. No modo de toque, blocos podem ser girados com a seta no canto inferior esquerdo. Aperte [yellow]próximo[] para tentar. -tutorial.placeDrill.text=Agora selecione e coloque uma [yellow]broca de pedra[] no local marcado. -tutorial.blockInfo.text=Se quiser saber mais sobre os blocos, você pode apertar o [orange]símbolo de interrogação[] no canto superior direito para ler mais. -tutorial.deselectDesktop.text=Você pode cancelar a seleção de um bloco usando o [orange][botão direito do mouse[]. -tutorial.deselectAndroid.text=ocê pode cancelar a seleção de um bloco apertando o botão [orange]X[]. -tutorial.drillPlaced.text=A broca produzirá [yellow]pedra[], direcionando o produzido para a esteira a qual moverá a pedra para o [yellow]núcleo[]. -tutorial.drillInfo.text=Minérios diferentes precisam de diferentes brocas. Pedra precisam de brocas de pedra, Ferro de brocas de ferro, etc. -tutorial.drillPlaced2.text=Itens movidos para o núcleo são colocados em seu [yellow]inventário[], no canto superior esquerdo. Colocar blocos gasta os recursos do inventário. -tutorial.moreDrills.text=Você pode conectar várias brocas e esteiras, veja. -tutorial.deleteBlock.text=Você pode excluir blocos clickando com o [orange]botão direito do mouse[] no bloco que quiser destruir. Tente excluir esta esteira. -tutorial.deleteBlockAndroid.text=Você pode excluir blocos [orange]apertando na cruz[] no [orange]menu modo de quebra[] no canto inferior esquerdo e então apertando no bloco desejado. Tente excluir esta esteira. -tutorial.placeTurret.text=Agora, selecione e construa uma [yellow]torre[] no [yellow]local marcado[]. -tutorial.placedTurretAmmo.text=Esta torre aceitará [yellow]munição[] da esteira. Você pode ver quanta munição elas tem passando o mouse sobre elas e verificando a [green]barra verde[]. -tutorial.turretExplanation.text=As torres irão atirar no inimigo mais próximo que estiver ao alcance, contanto que tenham munição suficiente. -tutorial.waves.text=A cada [yellow]60[] segundos, uma horda de [coral]inimigos[] irá aparecer em locais específicos e tentará destruir o núcleo. -tutorial.coreDestruction.text=Seu objetivo é [yellow]defender o núcleo[]. Se o núcleo for destruído, vecê [coral]perde o jogo[]. -tutorial.pausingDesktop.text=Se você precisar parar por alguns instantes, aperte o [orange]botão de pausa[] no canto superior esquerdo ou [orange]barra de espaço[] para pausar o jogo. Você pode colocar blocos enquanto o jogo esta pausado, porém não poderá se mover ou atirar. -tutorial.pausingAndroid.text=Se você precisar parar por alguns instantes, aperte o [orange]botão de pausa[] no canto superior esquerdo ou [orange]barra de espaço[] para pausar o jogo. Você pode colocar blocos enquanto o jogo esta pausado. -tutorial.purchaseWeapons.text=Você pode comprar novas [yellow]armas[] para seu mecha, basta abrir o menu de melhorias no canto inferior esquerdo. -tutorial.switchWeapons.text=Alterne entre suas armas clickando em seu ícone ou usando as teclas numéricas [orange][[1-9][]. -tutorial.spawnWave.text=Uma horda esta vindo. Destrúa-os. -tutorial.pumpDesc.text=Em hordas mais avançadas, você talvez precise de [yellow]bombas[] para distribuir líquidos para geradores ou extratores. -tutorial.pumpPlace.text=Bombas trabalham de forma semelhante às brocas, porém elas produzem líquidos ao envés de minérios. Tente colocar uma bomba na [yellow]célula de petróleo designada[]. -tutorial.conduitUse.text=Agora coloque um [orange]cano[] levando para longe da bomba. -tutorial.conduitUse2.text=E mais alguns... -tutorial.conduitUse3.text=E mais alguns... -tutorial.generator.text=Agora coloque um [orange]gerador a combustão[] no final do cano. -tutorial.generatorExplain.text=Este gerador irá produzir [yellow]energia[] do petróleo. -tutorial.lasers.text=Energia é distribuida usando [yellow]lasers[]. Gire e coloque um aqui. -tutorial.laserExplain.text=O gerador irá mover energia para o bloco do laser. Um feixe [yellow]opaco[] significa que a energia está sendo transmitida, e um feixe [yellow]transparente[] significa que não. -tutorial.laserMore.text=Você pode verificar quanta energia um bloco tem ao passar o mouse sobre eles e verificando a [yellow]barra amarela[] no topo. -tutorial.healingTurret.text=Este laser pode ser usado para energizar uma [lime]torre de reparo[]. Coloque uma aqui. -tutorial.healingTurretExplain.text=Enquanto tiver energia, esta torre irá [lime]reparar blocos próximos.[] Quando jogar, tenha certeza de construir uma dessas próximas do núcleo o mais rápido possível! -tutorial.smeltery.text=Muitos blocos precisam de [orange]aço[] para serem construídos, o que requer uma [orange]fundidora[] para ser feito. Coloque uma aqui. -tutorial.smelterySetup.text=Esta fundidora irá produzir [orange]aço[] quando receber carvão e ferro. -tutorial.end.text=E este é o fim do Tutorial! Boa Sorte! keybind.move_x.name=move_x keybind.move_y.name=move_y keybind.select.name=selecionar keybind.break.name=quebrar -keybind.shootInternal.name=atirar keybind.zoom_hold.name=segurar_zoom keybind.zoom.name=zoom keybind.menu.name=menu @@ -213,259 +126,370 @@ keybind.pause.name=pausar keybind.dash.name=Correr keybind.rotate_alt.name=girar_alt* keybind.rotate.name=girar -keybind.weapon_1.name=Arma 1 -keybind.weapon_2.name=Arma 2 -keybind.weapon_3.name=Arma 3 -keybind.weapon_4.name=Arma 4 -keybind.weapon_5.name=Arma 5 -keybind.weapon_6.name=Arma 6 mode.waves.name=hordas mode.sandbox.name=sandbox -#CAIXINHA DE AREIA mode.freebuild.name=construção \nlivre -weapon.blaster.name=Blaster -weapon.blaster.description=Atira um projétil lento e fraco. -weapon.triblaster.name=Blaster Triplo -weapon.triblaster.description=Atira 3 balas que se espalham. -weapon.multigun.name=Escopeta -weapon.multigun.description=Atira balas com baixa precisão e uma\n alta taxa de disparo. -weapon.flamer.name=Lança-Chamas -weapon.railgun.name=Rifle Sniper -weapon.flamer.description=É um lança-chamas. O que mais ele faria? -weapon.railgun.description=Atira um projétil de longo alcance. -weapon.mortar.name=Morteiro -weapon.mortar.description=Atira um projétil lento, porém devastador. item.stone.name=Pedra -item.iron.name=Ferro item.coal.name=Carvão -item.steel.name=Aço item.titanium.name=Titânio -item.dirium.name=Dírio item.thorium.name=Urânio liquid.water.name=Água -liquid.plasma.name=Plasma liquid.lava.name=Lava liquid.oil.name=Petróleo -block.air.name=Ar -block.blockpart.name=blockpart -#que? -block.deepwater.name=Água Profunda -block.water.name=Água -block.lava.name=Lava -block.oil.name=Petróleo -block.stone.name=Pedra -block.blackstone.name=Pedra Escura -block.iron.name=Ferro -block.coal.name=Carvão -block.titanium.name=Titânio -block.thorium.name=Urânio -block.dirt.name=Terra -block.sand.name=Areia -block.ice.name=Gelo -block.snow.name=Neve -block.grass.name=Grama -block.sandblock.name=Bloco de Areia -block.snowblock.name=Bloco de Neve -block.stoneblock.name=Rocha -block.blackstoneblock.name=Rocha Escura -block.grassblock.name=Bloco de Grama -block.mossblock.name=Musgo -block.shrub.name=Arbusto -block.rock.name=Rocha -block.icerock.name=Rocha de Gelo -block.blackrock.name=Rocha Escura -block.dirtblock.name=Bloco de Terra -block.stonewall.name=Parede de Pedra -block.stonewall.fulldescription=Um bloco defensivo barato. Útil para proteger o núcleo e torres nas primeiras hordas. -block.ironwall.name=Parede de Ferro -block.ironwall.fulldescription=Um bloco defensivo básico. Fornece proteção contra inimigos. -block.steelwall.name=Parede de aço -block.steelwall.fulldescription=Um bloco defensivo padrão. Fornece proteção contra inimigos. -block.titaniumwall.name=Parede de Titânio -block.titaniumwall.fulldescription=Um bloco defensivo forte. Fornece proteção contra inimigos. -block.duriumwall.name=Parede de Dírio -block.duriumwall.fulldescription=Um bloco defensivo muito forte. Fornece proteção contra inimigos. -block.compositewall.name=Parede de Composto -block.compositewall.fulldescription= Um bloco defensivo extremamente forte. Fornece a melhor proteção contra inimigos. -block.steelwall-large.name=Parede Grande de Aço -block.steelwall-large.fulldescription=Um bloco defensivo padrão. Ocupa multiplas células. -block.titaniumwall-large.name=Parede Grande de Titânio -block.titaniumwall-large.fulldescription=Um bloco defensivo forte. Ocupa multiplas células. -block.duriumwall-large.name=Parede Grande de Dírio -block.duriumwall-large.fulldescription=Um bloco defensivo muito forte. Ocupa multiplas células. -block.titaniumshieldwall.name=Parede com Escudo -block.titaniumshieldwall.fulldescription=Um bloco defensivo forte, com um escudo de energia imbutido. Usa energia passivamente e para absorver projéteis inimigos. É recomendado usar distribuidores de energia para abastecer este bloco. -#A strong defensive block, with an extra built-in shield. Requires power. Uses energy to absorb enemy bullets. It is recommended to use power boosters to provide energy to this block. -block.repairturret.name=Torre de Reparo -block.repairturret.fulldescription=Lentamente repara blocos danificados dentro do seu alcance. Consome um pouco de energia. -#Repairs nearby damaged blocks in range at a slow rate. Uses small amounts of power. -block.repairturret.description=[powerinfo]Consome Energia.[white]\nRepara blocos próximos. -block.megarepairturret.name=Torre de Reparo II -block.megarepairturret.fulldescription=Repara blocos danificados dentro do seu alcance. Consome um pouco de energia. -block.megarepairturret.description=[powerinfo]Consome Energia.[white]\nRepara blocos próximos. -block.shieldgenerator.name=Gerador de Escudo -block.shieldgenerator.fulldescription= Um bloco defensivo avançado. Protege todos os blocos em um raio. Lentamente usa energia quando parado, mas rapidamente drena em contato com projéteis. -#An advanced defensive block. Shields all the blocks in a radius from attack. Uses power at a slow rate when idle, but drains energy quickly on bullet contact. block.door.name=Porta -block.door.fulldescription=Um bloco que pode ser aberto e fechado ao tocar nele. -block.door.description=Abre e Fecha.\n[interact]Toque para alternar o estado. block.door-large.name=Porta Grande -block.door-large.fulldescription=Um bloco que pode ser aberto e fechado ao tocar nele. -block.door-large.description=Abre e Fecha.\n[interact]Toque para alternar o estado. block.conduit.name=Cano -block.conduit.fulldescription=Bloco de transporte de líquido básico. Funciona como uma esteira, mas com líquidos. Pode ser usado como uma ponte para inimigos e jogadores. -#Basic liquid transport block. Works like a conveyor, but with liquids. Best used with pumps or other conduits. Can be used as a bridge over liquids for enemies and players. block.pulseconduit.name=Cano de impulso -block.pulseconduit.fulldescription=Bloco de transporte de líquido avançado. Transporta líquidos mais rapidamente e armazena mais que canos normais. -#Advanced liquid transport block. Transports liquids faster and stores more than standard conduits. block.liquidrouter.name=Roteador de líquido -block.liquidrouter.fulldescription=Aceita líquido de uma direção e o redireciona para as outras 3 direções. Útil para dividir o líquido entre vários canos. -#Works similarly to a router. Accepts liquid input from one side and outputs it to the other sides. Useful for splitting liquid from a single conduit into multiple other conduits. -block.liquidrouter.description=Divide líquidos em 3 direções. block.conveyor.name=Esteira -block.conveyor.fulldescription=Bloco de transporte básico. Movimenta itens para frente e automaticamente os deposita em torres ou blocos de fabricação. Pode ser girado. Pode ser usado como uma ponte para inimigos e jogadores. -#Basic item transport block. Moves items forward and automatically deposits them into turrets or crafters. Rotatable. Can be used as a bridge over liquids for enemies and players. -block.steelconveyor.name=Esteira de aço -block.steelconveyor.fulldescription=Bloco de transporte avançado. Movimenta itens mais rapidamente que esteiras normais. -#Advanced item transport block. Moves items faster than standard conveyors. -block.poweredconveyor.name=Esteira de Impulso -block.poweredconveyor.fulldescription=O Bloco supremo de transporte. Movimenta itens mais rapidamente que esteiras de aço. -#The ultimate item transport block. Moves items faster than carbide conveyors. block.router.name=Roteador -block.router.fulldescription=Aceita itens de uma direção e os redireciona para as outras 3 direções. Pode guardar uma certa quantidade de itens. Útil para dividir materiais entre várias torres. block.router.description=Divide materiais em 3 direções. block.junction.name=Junção -block.junction.fulldescription=Funciona como uma ponte para 2 linhas de esteiras que se cruzam. Útil em situações onde duas esteiras carregam diferentes materiais para diferentes locais. -block.junction.description=Funciona como uma junção para as esteiras. -block.conveyortunnel.name=Túnel de esteira -block.conveyortunnel.fulldescription=Transporta itens por baixo de blocos. Para usar coloque um túnel apontado para o bloco que deseja passar por baixo, e outro apontado para o primeiro túnel. -block.conveyortunnel.description=Transporta intes por baixo de blocos. block.liquidjunction.name=Junção de líquido -block.liquidjunction.fulldescription=Funciona como uma ponte para 2 canos que se cruzam. Útil em situações onde 2 canos diferentes carregam diferentes líquidos para diferentes locais. -block.liquiditemjunction.name=liquid-item junction -block.liquiditemjunction.fulldescription=Acts as a bridge for crossing conduits and conveyors. -block.liquiditemjunction.description=Serves as a junction for items and liquids. -block.powerbooster.name=Distribuidor de energia -block.powerbooster.fulldescription=Distribui energia para todos os blocos dentro de seu raio. -block.powerbooster.description=Distribui energia em um raio. -block.powerlaser.name=Laser -#Laser de energia? -block.powerlaser.fulldescription=Cria um laser que transmite energia para o bloco à sua frente. Melhor usado com geradores ou outros lasers. Não gera energia. -block.powerlaser.description=Transmite energia. -block.powerlaserrouter.name=laser duplo -block.powerlaserrouter.fulldescription=Divide a entrada de energia em 3 lasers. Útil em situações onde é necessário conectar muitos blocos a partir de um gerador. -block.powerlaserrouter.description=Divide a entrada de energia em 3 lasers. -block.powerlasercorner.name=laser triplo -#*Essa nomeação ficou escrota -block.powerlasercorner.fulldescription=Laser que distribui energia para duas direções ao mesmo tempo. Útil em situações onde é necessário conectar muitos blocos a partir de um gerador. -block.powerlasercorner.description=Divide a entrada de energia em 2 lasers. -block.teleporter.name=Teleportador -block.teleporter.fulldescription=Bloco avançado de transporte de itens. Teleportadores transferem itens para outros teleportadores da mesma cor. Não faz nada se não houverem outros da mesma cor. Se houverem múltiplos da mesma cor, um aleatório será selecionado. Toque nas flechas para mudar de cor. -block.teleporter.description=[interact]Tap block to config[] block.sorter.name=Ordenador -block.sorter.fulldescription=Separa itens pelo tipo de material. O material a ser aceito é indicado pela cor do bloco. Todos os itens que correspondem ao material a ser separado são direcionados para frente, todo o resto é direcionado para os lados. block.sorter.description=[interact]Aperte no bloco para configurar[] -block.core.name=núcleo -block.pump.name=bomba -block.pump.fulldescription=Bombeia líquidos de um bloco, geralmente água, lava ou petróleo. Os líquidos são bombeados para canos próximos. -block.pump.description=Bombeia líquidos para canos próximos. -block.fluxpump.name=Bomba de fluxo -block.fluxpump.fulldescription=Uma versão avançada da bomba comum. Guarda mais líquido e bombeia mais rápido. -block.fluxpump.description=Bombeia líquidos para canos próximos. block.smelter.name=Fornalha -block.smelter.fulldescription=O bloco de produção essencial. Quando recebe 1 carvão e\n1 ferro produz 1 aço -block.smelter.description=Converte carvão + ferro em aço. -block.crucible.name=Usina de fundição -block.crucible.fulldescription=Um bloco de produção avançado. Quando recebe 1 titânio e 1 aço produz 1 dírio. -block.crucible.description=Converte aço + titânio em dírio. -block.coalpurifier.name=Extrator de carvão -block.coalpurifier.fulldescription=Um bloco extrator básico. Produz carvão quando fornecido com grandes quantidades de água e pedra. -block.coalpurifier.description=Converte pedra + água em carvão. -block.titaniumpurifier.name=Extrator de titânio -block.titaniumpurifier.fulldescription=Um bloco extrator padrão. Produz titânio quando fornecido com grandes quantidas de água e ferro. -block.titaniumpurifier.description=Converte água e ferro em titânio. -block.oilrefinery.name=Refinaria de Petróleo -block.oilrefinery.fulldescription=Refina grande quantidades de petróleo para produzir carvão. Útil para abastecer torres que utilizam carvão quando jazidas de carvão são escassas. -block.oilrefinery.description=Converte petróleo em carvão. -block.stoneformer.name=Formador de Pedra -block.stoneformer.fulldescription=Solidifica lava para formar pedra. Útil para produzir grandes quantidades de pedra para extratores de carvão. -block.stoneformer.description=Converte lava em pedra. -block.lavasmelter.name=Fornalha à Lava -block.lavasmelter.fulldescription=Usa lava para converter ferro em aço. Uma alternativa para a fundidora. Útil em situações onde não há carvão por perto. -block.lavasmelter.description=Converte ferro + lava em aço. -block.stonedrill.name=Broca de pedra -block.stonedrill.fulldescription=A broca essencial. Quando colocada em uma jazida de pedra gera pedra indefinidamente. -block.stonedrill.description=Gera 1 pedra a cada 4 segundos. -#Mines 1 stone every 4 seconds. -block.irondrill.name=Broca de Ferro -block.irondrill.fulldescription=Uma broca básica. Quando colocada sobre uma jazida de ferro, lentamente gera ferro. -#A basic drill. When placed on tungsten ore tiles, outputs tungsten at a slow pace indefinitely. -block.irondrill.description=Gera 1 ferro a cada 5 segundos. -block.coaldrill.name=Broca de Carvão -block.coaldrill.fulldescription=Uma broca básica. Quando colocada sobre uma jazida de carvão, lentamente gera carvão. -block.coaldrill.description=Gera 1 carvão a cada 5 segundos. -block.thoriumdrill.name=Broca de Urânio -block.thoriumdrill.fulldescription=Uma broca avançada. Quando colocada sobre uma jazida de urânio, lentamente gera urânio. -block.thoriumdrill.description=Gera 1 Urânio a cada 7 segundos. -block.titaniumdrill.name=Broca de Titânio -block.titaniumdrill.fulldescription=Uma broca avançada. Quando colocada sobre uma jazida de titânio, lentamente gera titânio. -block.titaniumdrill.description=Gera 1 Titânio a cada 5 segundos. -block.omnidrill.name=Omnibroca -block.omnidrill.fulldescription=A broca suprema. Rapidamente extrai qualquer minério em que é colocada. -#The ultimate drill. Will mine any ore it is placed on at a rapid pace. -block.omnidrill.description=Gera 1 de qualquer recurso a cada 3 segundos. -block.coalgenerator.name=Gerador à Carvão -#Crase ou não? -block.coalgenerator.fulldescription=O gerador essencial. Gera energia a partir de carvão. Distribui energia em forma de laser para os 4 lados. -block.coalgenerator.description=Gera energia a partir de carvão. -block.thermalgenerator.name=Gerador Térmico -block.thermalgenerator.fulldescription=Gera energia a partir de lava. Distribui energia em forma de laser para os 4 lados. -block.thermalgenerator.description=Gera energia a partir de lava. -block.combustiongenerator.name=Gerador à Combustão -block.combustiongenerator.fulldescription=Gera energia a partir de petróleo. Distribui energia em forma de laser para os 4 lados. -block.combustiongenerator.description=Gera energia a partir de petróleo. -block.rtgenerator.name=Gerador RTG -block.rtgenerator.fulldescription=Gera pouca quantidade de energia a partir do decaimento radioativo do urânio. Distribui energia em forma de laser para os 4 lados. -block.rtgenerator.description=Gera energia a partir de Urânio. -block.nuclearreactor.name=Reator Nuclear -block.nuclearreactor.fulldescription=Uma versão avançada do gerador RTG. Gera energia a partir de Urânio. Requer constante resfriamento à água. Altamente volátil; explodirá violentamente se não for suprido com quantiddades suficientes de água. -block.turret.name=Torre Comum -block.turret.fulldescription=Uma torre básica e barata. Usa pedra como munição. Tem alcance um pouco maior que a torre dupla. -block.turret.description=[turretinfo]Munição: pedra -block.doubleturret.name=Torre Dupla -block.doubleturret.fulldescription=Uma versão um pouco mais poderosa do que a torre comum. Usa pedra como munição. Causa um dano maior, porém tem menor alcance. Atira dois projéteis. -block.doubleturret.description=[turretinfo]Munição: pedra -block.machineturret.name=Torre Automática -block.machineturret.fulldescription=Uma torre padrão completa. Usa ferro como munição. Tem alta taxa de disparo e dano decente. -block.machineturret.description=[turretinfo]Munição: ferro -block.shotgunturret.name=Torre Splitter -#Splitter turret -block.shotgunturret.fulldescription=Uma torre padrão. Usa ferro como munição. Atira 7 balas em forma de cone. Pouco alcance, porém maior dano do que a Torre Dupla. -block.shotgunturret.description=[turretinfo]Munição: ferro -block.flameturret.name=Torre lança-\nchamas -block.flameturret.fulldescription=Torre avançada de baixo alcance. Usa carvão. Pouco alcance mas alto dano. Boa para trechos estreitos. Recomenda-se usá-la atŕas de paredes. -block.flameturret.description=[turretinfo]Munição: carvão -block.sniperturret.name=Torre Sniper -#Torre Railgun? -block.sniperturret.fulldescription=Torre avançada de longo alcance. Usa aço como munição. Dano altíssimo, porém baixa taxa de disparo. Cara para usar, porém pode ser colocada longe das linhas inimigas dado seu alcance. -block.sniperturret.description=[turretinfo]Munição: aço -block.mortarturret.name=Torre Flak -block.mortarturret.fulldescription=Torre avançada de dano em área. Usa carvão. Taxa de disparo e balas lentas, mas alto dano em alvo único ou distribuído. -block.mortarturret.description=[turretinfo]Munição: carvão -block.laserturret.name=Torre laser -block.laserturret.fulldescription=Torre de alvo único avançada. Usa energia. Boa torre de alcance médio e uso geral. Alvo único apenas. Nunca erra. -block.laserturret.description=[turretinfo]Usa Energia -block.waveturret.name=Torre Tesla -block.waveturret.fulldescription=Torre de múltiplos alvos avançada. Usa Energia. Alcance médio. Nunca erra. Dano médio-baixo, porém pode acertar vários inimigos simultaneamente com raios conectados. -block.waveturret.description=[turretinfo]Usa Energia -block.plasmaturret.name=Torre de Plasma -block.plasmaturret.fulldescription=Versão altamente avançada da Torre lança-chamas. Usa carvão. Dano altíssimo e alcance médio-baixo. -block.plasmaturret.description=[turretinfo]Munição: carvão -block.chainturret.name=Canhão automático -block.chainturret.fulldescription=A torre de tiro rápido mais avançada. Usa Urânio como munição. Atira grandes projéteis rapidamente. Alcance médio. Ocupa várias células. Extremamente resistente. -block.chainturret.description=[turretinfo]Munição: Urânio -block.titancannon.name=Canhão Titã -block.titancannon.fulldescription=A torre de longo alcance mais avançada. Usa Urânio como munição. Atira várias balas de dano em área à uma taxa de disparo média. Alto alcance. Ocupa várias células. Extremamente resistente. -block.titancannon.description=[turretinfo]Munição: Urânio -block.playerspawn.name=playerspawn -block.enemyspawn.name=enemyspawn +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.joingame=Join Game +text.addplayers=Add/Remove Players +text.newgame=New Game +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.about.button=About +text.name=Name: +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.players={0} players online +text.players.single={0} player online +text.server.mismatch=Packet error: possible client/server version mismatch.\nMake sure you and the host have the\nlatest version of Mindustry! +text.server.closing=[accent]Closing server... +text.server.kicked.kick=You have been kicked from the server! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.invalidPassword=Invalid password! +text.server.kicked.clientOutdated=Outdated client! Update your game! +text.server.kicked.serverOutdated=Outdated server! Ask the host to update! +text.server.kicked.banned=You are banned on this server. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.server.connected={0} has joined. +text.server.disconnected={0} has disconnected. +text.nohost=Can't host server on a custom map! +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.hostserver=Host Server +text.host=Host +text.hosting=[accent]Opening server... +text.hosts.refresh=Refresh +text.hosts.discovering=Discovering LAN games +text.server.refreshing=Refreshing server +text.hosts.none=[lightgray]No LAN games found! +text.host.invalid=[scarlet]Can't connect to host. +text.server.friendlyfire=Friendly Fire +text.trace=Trace Player +text.trace.playername=Player name: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Unique ID: [accent]{0} +text.trace.android=Android Client: [accent]{0} +text.trace.modclient=Custom Client: [accent]{0} +text.trace.totalblocksbroken=Total blocks broken: [accent]{0} +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.trace.lastblockbroken=Last block broken: [accent]{0} +text.trace.totalblocksplaced=Total blocks placed: [accent]{0} +text.trace.lastblockplaced=Last block placed: [accent]{0} +text.invalidid=Invalid client ID! Submit a bug report. +text.server.bans=Bans +text.server.bans.none=No banned players found! +text.server.admins=Admins +text.server.admins.none=No admins found! +text.server.add=Add Server +text.server.delete=Are you sure you want to delete this server? +text.server.hostname=Host: {0} +text.server.edit=Edit Server +text.server.outdated=[crimson]Outdated Server![] +text.server.outdated.client=[crimson]Outdated Client![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[yellow]Custom Build +text.confirmban=Are you sure you want to ban this player? +text.confirmunban=Are you sure you want to unban this player? +text.confirmadmin=Are you sure you want to make this player an admin? +text.confirmunadmin=Are you sure you want to remove admin status from this player? +text.joingame.title=Join Game +text.joingame.ip=IP: +text.disconnect=Disconnected. +text.disconnect.data=Failed to load world data! +text.connecting=[accent]Connecting... +text.connecting.data=[accent]Loading world data... +text.connectfail=[crimson]Failed to connect to server: [orange]{0} +text.server.port=Port: +text.server.addressinuse=Address already in use! +text.server.invalidport=Invalid port number! +text.server.error=[crimson]Error hosting server: [orange]{0} +text.save.new=New Save +text.save.none=No saves found! +text.save.delete.confirm=Are you sure you want to delete this save? +text.save.delete=Delete +text.save.export=Export Save +text.save.import.invalid=[orange]This save is invalid! +text.save.import.fail=[crimson]Failed to import save: [orange]{0} +text.save.export.fail=[crimson]Failed to export save: [orange]{0} +text.save.import=Import Save +text.save.newslot=Save name: +text.save.rename=Rename +text.save.rename.text=New name: +text.on=On +text.off=Off +text.save.autosave=Autosave: {0} +text.save.map=Map: {0} +text.save.difficulty=Difficulty: {0} +text.copylink=Copy Link +text.changelog.title=Changelog +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.language.restart=Please restart your game for the language settings to take effect. +text.settings.language=Language +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.info.title=[accent]Info +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.blocks.inputcapacity=Input capacity +text.blocks.outputcapacity=Output capacity +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.difficulty.insane=insane +setting.difficulty.purge=purge +setting.saveinterval.name=Autosave Interval +setting.seconds={0} Seconds +setting.fullscreen.name=Fullscreen +setting.multithread.name=Multithreading +setting.minimap.name=Show Minimap +text.keybind.title=Rebind Keys +keybind.shoot.name=shoot +keybind.block_info.name=block_info +keybind.chat.name=chat +keybind.player_list.name=player_list +keybind.console.name=console +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.name=Sand +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 8a8102b84e..81593c7e58 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -1,555 +1,495 @@ -text.about = Создатель [ROYAL] Anuken. [] \nИзначально игра была создана для участия в [orange] GDL [] MM Jam. \n\nАвторы: \n- Звуковые эффекты, сделаны с помощью [YELLOW] bfxr [] \n- Музыка, создана [GREEN] RoccoW [] / найденная на [lime] FreeMusicArchive.org [] \n\nОсобая благодарность: \n- [coral] MitchellFJN []: в тестировании и отзывах \n- [sky] Luxray5474 []: работа в вики, помощь в разработке \n- Все бета-тестеры на itch.io и Google Play\n\nИгра переведена полностью на русский язык [GREEN]krocotavus[] и [GREEN]lexa1549. Дополнил перевод [GREEN]Prosta4ok_ua[]\n -text.credits = Авторы -text.discord = Присоединяйтесь к нашему Discord чату! -text.changes=[SCARLET] Внимание!\n[]Изменена некоторая важная игровая механика.\n\n-[accent]Телепортеры[]теперь используют силу.\n-[accent]Печи[]и[accent]тигли[]теперь имеют максимальная емкость элемента.\n-[accent]Тигли[]теперь требует угля в качестве топлива. -text.link.discord.description = официальный discord-сервер Mindustry -text.link.github.description = Исходный код игры -text.link.dev-builds.description = Нестабильные разработки -text.link.trello.description = Официальная доска trello для запланированных функций -text.link.itch.io.description = itch.io страница с загрузкой ПК и веб-версией -text.link.google-play.description = Google Play список магазинов -text.link.wiki.description = официальная вики Mindustry -text.linkfail = Не удалось открыть ссылку!\nURL-адрес был скопирован в буфер обмена. -text.editor.web = Веб-версия не поддерживает редактор!\nЗагрузите игру, чтобы использовать ее. -text.multiplayer.web = Эта версия игры не поддерживает многопользовательскую игру! \n Чтобы играть в мультиплеер из своего браузера, используйте ссылку «Многопользовательская веб-версия» на странице itch.io. -text.gameover = Ядро было уничтожено. -text.highscore = [YELLOW]Новый рекорд! -text.lasted = Вы продержались до волны -text.level.highscore = Рекорд: [accent]{0} -text.level.delete.title = Подтвердите удаление -text.level.delete = Вы уверены,что хотите удалить эту карту \"[orange]\"{0}? -text.level.select = Выбор уровня -text.level.mode = Режим игры: -text.savegame = Сохранить игру -text.loadgame = Загрузить игру -text.joingame = Присоединиться -text.newgame= Новая игра -text.quit = Выход -text.about.button = Об игре -text.name = Название: -text.public = Общие -text.players = Игроков на сервере: {0} -text.server.player.host={0} (хост) -text.players.single = {0} игрок на сервере -text.server.mismatch = Ошибка пакета: возможное несоответствие версии клиента / сервера. Убедитесь, что у вас и у создателя сервера установлена ​​последняя версия Mindustry! -text.server.closing = [accent]Закрытие сервера... -text.server.kicked.kick = Вас выгнали с сервера! -text.server.kicked.fastShoot = Вы стреляете слишком быстро. -text.server.kicked.invalidPassword = Неверный пароль. -text.server.kicked.clientOutdated = Устаревший клиент! Обновите игру! -text.server.kicked.serverOutdated = Устаревший сервер! Попросите хост обновить! -text.server.kicked.banned = Вы заблокированы на этом сервере. +text.about=Создатель [ROYAL] Anuken. [] \nИзначально игра была создана для участия в [orange] GDL [] MM Jam. \n\nАвторы: \n- Звуковые эффекты, сделаны с помощью [YELLOW] bfxr [] \n- Музыка, создана [GREEN] RoccoW [] / найденная на [lime] FreeMusicArchive.org [] \n\nОсобая благодарность: \n- [coral] MitchellFJN []: в тестировании и отзывах \n- [sky] Luxray5474 []: работа в вики, помощь в разработке \n- Все бета-тестеры на itch.io и Google Play\n\nИгра переведена полностью на русский язык [GREEN]krocotavus[] и [GREEN]lexa1549. Дополнил перевод [GREEN]Prosta4ok_ua[]\n +text.credits=Авторы +text.discord=Присоединяйтесь к нашему Discord чату! +text.link.discord.description=официальный discord-сервер Mindustry +text.link.github.description=Исходный код игры +text.link.dev-builds.description=Нестабильные разработки +text.link.trello.description=Официальная доска trello для запланированных функций +text.link.itch.io.description=itch.io страница с загрузкой ПК и веб-версией +text.link.google-play.description=Google Play список магазинов +text.link.wiki.description=официальная вики Mindustry +text.linkfail=Не удалось открыть ссылку!\nURL-адрес был скопирован в буфер обмена. +text.editor.web=Веб-версия не поддерживает редактор!\nЗагрузите игру, чтобы использовать ее. +text.multiplayer.web=Эта версия игры не поддерживает многопользовательскую игру! \n Чтобы играть в мультиплеер из своего браузера, используйте ссылку «Многопользовательская веб-версия» на странице itch.io. +text.gameover=Ядро было уничтожено. +text.highscore=[YELLOW]Новый рекорд! +text.lasted=Вы продержались до волны +text.level.highscore=Рекорд: [accent]{0} +text.level.delete.title=Подтвердите удаление +text.level.select=Выбор уровня +text.level.mode=Режим игры: +text.savegame=Сохранить игру +text.loadgame=Загрузить игру +text.joingame=Присоединиться +text.newgame=Новая игра +text.quit=Выход +text.about.button=Об игре +text.name=Название: +text.players=Игроков на сервере: {0} +text.players.single={0} игрок на сервере +text.server.mismatch=Ошибка пакета: возможное несоответствие версии клиента / сервера. Убедитесь, что у вас и у создателя сервера установлена ​​последняя версия Mindustry! +text.server.closing=[accent]Закрытие сервера... +text.server.kicked.kick=Вас выгнали с сервера! +text.server.kicked.fastShoot=Вы стреляете слишком быстро. +text.server.kicked.invalidPassword=Неверный пароль. +text.server.kicked.clientOutdated=Устаревший клиент! Обновите игру! +text.server.kicked.serverOutdated=Устаревший сервер! Попросите хост обновить! +text.server.kicked.banned=Вы заблокированы на этом сервере. text.server.kicked.recentKick=Вы недавно были кикнуты.\n Подождите немного перед следующим подключением -text.server.connected = {0} присоединился -text.server.disconnected = {0} отключился. -text.nohost = Не удается запустить сервер на пользовательской карте! +text.server.connected={0} присоединился +text.server.disconnected={0} отключился. +text.nohost=Не удается запустить сервер на пользовательской карте! text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. -text.hostserver = Запустить сервер -text.host = Сервер -text.hosting = [accent]Открытие сервера... -text.hosts.refresh = Обновить -text.hosts.discovering = Поиск локальных игр -text.server.refreshing = Обновление сервера -text.hosts.none = [lightgray]Локальных игр не обнаружено! -text.host.invalid = [scarlet] Не удается подключиться к хосту. -text.server.friendlyfire = Дружественный огонь -text.trace = Слежка за игроком -text.trace.playername = Имя игрока: [accent]{0} -text.trace.ip = IP: [accent]{0} -text.trace.id = Уникальный идентификатор: [accent]{0} -text.trace.android = Клиент Android: [accent]{0} -text.trace.modclient = Пользовательский клиент: [accent]{0} -text.trace.totalblocksbroken = Всего разбитых блоков: [accent]{0} - -e.structureblocksbroken = Структурных блоков сломанных: [accent]{0} -text.trace.lastblockbroken = Последний сломанный блок:[accent]{0} -text.trace.totalblocksplaced = Всего размещено блоков: [accent]{0} -text.trace.lastblockplaced = Последний размещенный блок: [accent]{0} -text.invalidid = Недопустимый идентификатор клиента! Отправьте отчет об ошибке. -text.server.bans = Блокировки -text.server.bans.none = Никаких заблокированных игроков не найдено! -text.server.admins = Администраторы -text.server.admins.none = Администраторов не найдено! -text.server.add = Добавить сервер -text.server.delete = Вы действительно хотите удалить этот сервер? -text.server.hostname = Хост: {0} -text.server.edit = Редактировать сервер -text.server.outdated = [crimson]Устаревший сервер![] -text.server.outdated.client = [crimson]Устаревший клиент![] -text.server.version = [lightgray]Версия: {0} +text.hostserver=Запустить сервер +text.host=Сервер +text.hosting=[accent]Открытие сервера... +text.hosts.refresh=Обновить +text.hosts.discovering=Поиск локальных игр +text.server.refreshing=Обновление сервера +text.hosts.none=[lightgray]Локальных игр не обнаружено! +text.host.invalid=[scarlet] Не удается подключиться к хосту. +text.server.friendlyfire=Дружественный огонь +text.trace=Слежка за игроком +text.trace.playername=Имя игрока: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Уникальный идентификатор: [accent]{0} +text.trace.android=Клиент Android: [accent]{0} +text.trace.modclient=Пользовательский клиент: [accent]{0} +text.trace.totalblocksbroken=Всего разбитых блоков: [accent]{0} +text.trace.lastblockbroken=Последний сломанный блок:[accent]{0} +text.trace.totalblocksplaced=Всего размещено блоков: [accent]{0} +text.trace.lastblockplaced=Последний размещенный блок: [accent]{0} +text.invalidid=Недопустимый идентификатор клиента! Отправьте отчет об ошибке. +text.server.bans=Блокировки +text.server.bans.none=Никаких заблокированных игроков не найдено! +text.server.admins=Администраторы +text.server.admins.none=Администраторов не найдено! +text.server.add=Добавить сервер +text.server.delete=Вы действительно хотите удалить этот сервер? +text.server.hostname=Хост: {0} +text.server.edit=Редактировать сервер +text.server.outdated=[crimson]Устаревший сервер![] +text.server.outdated.client=[crimson]Устаревший клиент![] +text.server.version=[lightgray]Версия: {0} text.server.custombuild=[yellow]Пользовательская сборка -text.confirmban = Вы действительно хотите заблокировать этого игрока? -text.confirmunban = Вы действительно хотите разблокировать этого игрока? -text.confirmadmin = Вы уверены, что хотите сделать этого игрока администратором? -text.confirmunadmin = Вы действительно хотите удалить статус администратора с этого игрока? -text.joingame.byip = Присоединиться по IP ... -text.joingame.title = Присоединиться к игре -text.joingame.ip = IP: -text.disconnect = Отключён\n -text.disconnect.data = Не удалось загрузить данные мира! -text.connecting = [accent]Подключение... -text.connecting.data = [accent]Загрузка данных мира... -text.connectfail = [crimson]Не удалось подключиться к серверу: [orange] {0} -text.server.port = Порт: +text.confirmban=Вы действительно хотите заблокировать этого игрока? +text.confirmunban=Вы действительно хотите разблокировать этого игрока? +text.confirmadmin=Вы уверены, что хотите сделать этого игрока администратором? +text.confirmunadmin=Вы действительно хотите удалить статус администратора с этого игрока? +text.joingame.title=Присоединиться к игре +text.joingame.ip=IP: +text.disconnect=Отключён\n +text.disconnect.data=Не удалось загрузить данные мира! +text.connecting=[accent]Подключение... +text.connecting.data=[accent]Загрузка данных мира... +text.connectfail=[crimson]Не удалось подключиться к серверу: [orange] {0} +text.server.port=Порт: text.server.addressinuse=Адрес уже используется! -text.server.invalidport = Неверный номер порта! -text.server.error = [crimson]Ошибка создания сервера: [orange] {0} -text.tutorial.back = <назад -text.tutorial.next = далее> -text.save.new = Новое сохранение -text.save.overwrite = Вы уверены,что хотите перезаписать этот слот для сохранения? -text.overwrite = Перезаписать -text.save.none = Сохранения не найдены! -text.saveload = [accent]Сохранение... -text.savefail = Не удалось сохранить игру! -text.save.delete.confirm = Вы уверены,что хотите удалить это сохранение? -text.save.delete = Удалить -text.save.export = Отправить сохранение -text.save.import.invalid = [orange]Это сохранение недействительно! -text.save.import.fail = [crimson]Не удалось импортировать сохранение: [orange] {0} -text.save.export.fail = [crimson]Не удалось отправить сохранение: [orange] {0} -text.save.import = Импортировать сохранение -text.save.newslot = Имя сохранения: -text.save.rename = Переименовывать -text.save.rename.text = Новое название: -text.selectslot = Выберите сохранение. -text.slot = [accent]Слот {0} -text.save.corrupted = [orange]Файл сохранения поврежден или имеет недействительный формат! -text.empty = <Пусто> -text.on = Вкл -text.off = Выкл -text.save.autosave = Автосохранение: {0} -text.save.map = Карта: {0} -text.save.wave = Волна: {0} -text.save.difficulty = Сложность: {0} -text.save.date = Последнее сохранение: {0} -text.confirm = Подтвердить -text.delete = Удалить -text.ok = ОК -text.open = Открыть -text.cancel = Отмена -text.openlink = Открыть ссылку -text.copylink = Скопировать ссылку -text.back = Назад -text.quit.confirm = Вы уверены, что хотите выйти? -text.changelog.title = Список изменений -text.changelog.loading = Получение изменений ... -text.changelog.error.android = [orange]Обратите внимание, что журнал изменений иногда не работает на Android 4.4 и ниже!\nЭто связано с внутренней ошибкой Android. -text.changelog.error.ios = [orange]В настоящее время журнал изменений не поддерживается iOS. -text.changelog.error = [scarlet]Ошибка при получении изменений!\nПроверьте подключение к Интернету. +text.server.invalidport=Неверный номер порта! +text.server.error=[crimson]Ошибка создания сервера: [orange] {0} +text.save.new=Новое сохранение +text.save.overwrite=Вы уверены,что хотите перезаписать этот слот для сохранения? +text.overwrite=Перезаписать +text.save.none=Сохранения не найдены! +text.saveload=[accent]Сохранение... +text.savefail=Не удалось сохранить игру! +text.save.delete.confirm=Вы уверены,что хотите удалить это сохранение? +text.save.delete=Удалить +text.save.export=Отправить сохранение +text.save.import.invalid=[orange]Это сохранение недействительно! +text.save.import.fail=[crimson]Не удалось импортировать сохранение: [orange] {0} +text.save.export.fail=[crimson]Не удалось отправить сохранение: [orange] {0} +text.save.import=Импортировать сохранение +text.save.newslot=Имя сохранения: +text.save.rename=Переименовывать +text.save.rename.text=Новое название: +text.selectslot=Выберите сохранение. +text.slot=[accent]Слот {0} +text.save.corrupted=[orange]Файл сохранения поврежден или имеет недействительный формат! +text.empty=<Пусто> +text.on=Вкл +text.off=Выкл +text.save.autosave=Автосохранение: {0} +text.save.map=Карта: {0} +text.save.wave=Волна: {0} +text.save.difficulty=Сложность: {0} +text.save.date=Последнее сохранение: {0} +text.confirm=Подтвердить +text.delete=Удалить +text.ok=ОК +text.open=Открыть +text.cancel=Отмена +text.openlink=Открыть ссылку +text.copylink=Скопировать ссылку +text.back=Назад +text.quit.confirm=Вы уверены, что хотите выйти? +text.changelog.title=Список изменений +text.changelog.loading=Получение изменений ... +text.changelog.error.android=[orange]Обратите внимание, что журнал изменений иногда не работает на Android 4.4 и ниже!\nЭто связано с внутренней ошибкой Android. +text.changelog.error.ios=[orange]В настоящее время журнал изменений не поддерживается iOS. +text.changelog.error=[scarlet]Ошибка при получении изменений!\nПроверьте подключение к Интернету. text.changelog.current=[yellow][[Текущая версия] text.changelog.latest=[orange][[Последняя версия] -text.loading = [accent] Загрузка... -text.wave = [orange]Волна {0} -text.wave.waiting = Волна через {0} -text.waiting = Ожидание... -text.enemies = {0} Противников -text.enemies.single = {0} Противник -text.loadimage = Загрузить изображение -text.saveimage = Сохранить изображение -text.oregen = Генерация руд -text.editor.badsize = [orange]Недопустимый формат изображения! [] \nДопустимый формат карты: {0} -text.editor.errorimageload = Ошибка загрузки изображения: [orange] {0} -text.editor.errorimagesave = Ошибка сохранения изображения: [orange] {0} -text.editor.generate = Создать -text.editor.resize = Изменить \nразмер -text.editor.loadmap = Загрузить\nкарту -text.editor.savemap = Сохранить\nкарту -text.editor.loadimage = Загрузить \nизображение -text.editor.saveimage = Сохранить \nизображение -text.editor.unsaved = [scarlet]У вас есть не сохраненные изменения![] \nВы уверены,что хотите выйти? -text.editor.brushsize = Размер кисти: {0} -text.editor.noplayerspawn = На этой карте нет точки появления игрока! -text.editor.manyplayerspawns = На карте не может быть больше одной точки появления игрока! -text.editor.manyenemyspawns = Не может быть больше {0} вражеских точек появления! -text.editor.resizemap = Изменить размер карты -text.editor.resizebig = [scarlet]Внимание! \n[]Карты размером больше 256 единиц могут быть не стабильны и тормозить. -text.editor.mapname = Название карты: -text.editor.overwrite = [accent]Внимание! \nЭто перезапишет уже существующую карту. -text.editor.failoverwrite = [crimson]Невозможно перезаписать стандартную карту! -text.editor.selectmap = Выберите карту для загрузки: -text.width = Ширина: -text.height = Высота: -text.randomize = Рандомизировать -text.apply = Применить -text.update = Обновить -text.menu = Меню -text.play = Играть -text.load = Загрузить -text.save = Сохранить -text.language.restart = Перезагрузите игру, чтобы настройки языка вступили в силу. -text.settings.language = Язык -text.settings = Настройки -text.tutorial = Обучение -text.editor = Редактор -text.mapeditor = Редактор карт -text.donate = Донат -text.settings.reset = Сбросить по умолчанию -text.settings.controls = Управление -text.settings.game = Игра -text.settings.sound = Звук -text.settings.graphics = Графика -text.upgrades = Улучшения -text.purchased = [LIME]Создан! -text.weapons = Оружие -text.paused = Пауза -text.respawn = Возрождение через -text.info.title = [accent]Информация -text.error.title = [crimson]Произошла ошибка -text.error.crashmessage = [SCARLET]Произошла непредвиденная ошибка,которая могла вызвать сбой.[]Пожалуйста, сообщите точные обстоятельства разработчику,при которых эта ошибка возникла : [ORANGE]anukendev@gmail.com[] -text.error.crashtitle = Произошла ошибка -text.mode.break = Режим сноса: {0} -text.mode.place = Режим размещения: {0} -placemode.hold.name = линия -placemode.areadelete.name = зона -placemode.touchdelete.name = касание -placemode.holddelete.name = удержание -placemode.none.name = ничего -placemode.touch.name = Касание -placemode.cursor.name = курсор -text.blocks.extrainfo = [accent]дополнительная информация о блоке: -text.blocks.blockinfo = Информация о блоке -text.blocks.powercapacity = Вместимость энергии -text.blocks.powershot = Энергия / выстрел -text.blocks.powersecond = Энергия / в секунду -text.blocks.powerdraindamage = Поглощение энергии / урон -text.blocks.shieldradius = Радиус щита -text.blocks.itemspeedsecond = Скорость предметов / в секунду -text.blocks.range = Дальность -text.blocks.size = Размер -text.blocks.powerliquid = Энергия / Жидкость -text.blocks.maxliquidsecond = Макс. Жидкость / в секунду -text.blocks.liquidcapacity = Вместимость жидкости -text.blocks.liquidsecond = Жидкость / в секунду -text.blocks.damageshot = Урон / выстрел -text.blocks.ammocapacity = Вместимость боеприпасов -text.blocks.ammo = боеприпасы -text.blocks.ammoitem = боеприпасы / предмет -text.blocks.maxitemssecond = Макс. Количество предметов / в секунду -text.blocks.powerrange = Диапазон мощности энергии -text.blocks.lasertilerange = Дальность лазера -text.blocks.capacity = Вместимость -text.blocks.itemcapacity = Вместимость предметов -text.blocks.maxpowergenerationsecond = Макс. выработка энергии / в секунду -text.blocks.powergenerationsecond = Выработка энергии / в секунду -text.blocks.generationsecondsitem = Выработка секунд / предмет -text.blocks.input = Прием -text.blocks.inputliquid = Прием жидкости -text.blocks.inputitem = Прием предмета -text.blocks.output = Вывод -text.blocks.secondsitem = Секунды / предмет -text.blocks.maxpowertransfersecond = Максимальная передача энергии / секунда -text.blocks.explosive = Взрывоопасно! -text.blocks.repairssecond = Ремонт / в секунду -text.blocks.health = Здоровье -text.blocks.inaccuracy = Разброс -text.blocks.shots = Выстрелы -text.blocks.shotssecond = Выстрелов / в секунду -text.blocks.fuel = топливо -text.blocks.fuelduration = Продолжительность действия топлива -text.blocks.maxoutputsecond = Макс. Вывод / в секунду -text.blocks.inputcapacity = Вместимость ввода -text.blocks.outputcapacity = Вместимость вывода -text.blocks.poweritem = Энергия / предмет -text.placemode = Режим размещения -text.breakmode = Режим сноса -text.health = здоровье -setting.difficulty.easy = легко -setting.difficulty.normal = нормально -setting.difficulty.hard = тяжело -setting.difficulty.insane = нереально -setting.difficulty.purge = зачистка -setting.difficulty.name = Сложность -setting.screenshake.name = Дрожание экрана -setting.smoothcam.name = Плавная камера -setting.indicators.name = Индикаторы противников -setting.effects.name = Эффекты на экране -setting.sensitivity.name = Чувствительность контроллера -setting.saveinterval.name = Интервал автосохранения -setting.seconds = {0} Секунд -setting.fullscreen.name = Полноэкранный -setting.multithread.name = Многопоточность -setting.fps.name = Показать FPS -setting.vsync.name = Верт. синхронизация -setting.lasers.name = Показывать энергетические лазеры -setting.previewopacity.name = Прозрачность объкта при предв. просм. -setting.healthbars.name = Показать полоски здоровья объекта -setting.pixelate.name = Пикселизация экрана -setting.musicvol.name = Громкость музыки -setting.mutemusic.name = Заглушить музыку -setting.sfxvol.name = Громкость звуковых эффектов -setting.mutesound.name = Заглушить звук -map.maze.name = лабиринт -map.fortress.name = крепость -map.sinkhole.name = раковина -map.caves.name = пещеры -map.volcano.name = вулкан -map.caldera.name = кальдера -map.scorch.name = горение -map.desert.name = пустыня -map.island.name = остров -map.grassland.name = луг -map.tundra.name = тундра -map.spiral.name = спираль -map.tutorial.name = обучение -tutorial.intro.text = [yellow]Добро пожаловать в обучение.[] Чтобы начать нажмите «далее». -tutorial.moveDesktop.text = Для перемещения используйте [orange][[WASD][] клавиши. Удерживайте [orange]shift[] для ускорения. Удерживайте [orange]CTRL[] при использовании [orange]​​колесика мыши[] для увеличения или уменьшения масштаба. -tutorial.shoot.text = Используйте мышь для прицеливания, удерживайте [orange]левую кнопку мыши[],чтобы выстрелить. Попробуйте на [yellow]цели[]. -tutorial.moveAndroid.text = Чтобы изменить вид, перетащите палец по экрану. Зажмите и разведите двумя пальцами,чтобы увеличить или уменьшить степень приближения. -tutorial.placeSelect.text = Попробуйте выбрать [yellow]конвейер[] из меню блоков внизу справа. -tutorial.placeConveyorDesktop.text = Используйте [orange][[колёсико мыши][],чтобы повернуть конвейер лицом [orange]вперед[], поместите его в [yellow]отмеченное место[],используя [orange][[левую кнопку мыши]]. -tutorial.placeConveyorAndroid.text = Используйте [orange][[кнопку поворота][], чтобы повернуть конвейер лицом [orange]вперед[], перетащите его на место одним пальцем, затем поместите его в [yellow]отмеченное место[],используя [orange][[галочку][]. -tutorial.placeConveyorAndroidInfo.text = Кроме того, вы можете нажать на значок перекрестия в левом нижнем углу, чтобы перейти в [orange][[режим касания][] и поместить блоки, нажав на экран. В режиме касания блоки можно поворачивать стрелкой в ​​левом нижнем углу. Нажмите [yellow]далее[],чтобы попробовать. -tutorial.placeDrill.text = Теперь, выберите и поместите [yellow]каменный бур[] в отмеченное место. -tutorial.blockInfo.text = Если вы хотите узнать больше о блоке, вы можете нажать на [orange]знак вопроса[] в правом верхнем углу, чтобы прочитать его описание. -tutorial.deselectDesktop.text = Вы можете отменить выбор блока, используя [orange][[правую кнопку мыши][]. -tutorial.deselectAndroid.text = Вы можете отменить выбор блока, нажав кнопку [orange]X[]. -tutorial.drillPlaced.text = Бур теперь производит [yellow]камень,[] выведет его на конвейер, а затем переместит его в [yellow]ядро​[] -tutorial.drillInfo.text = Разным рудам нужны разные буры. Камень требует каменный бур, железо требует железный бур и т.д. -tutorial.drillPlaced2.text = Перемещение предметов в ядро ​​помещает их в ваш [yellow]инвентарь для предметов[], в левом верхнем углу. Размещение блоков использует предметы из вашего инвентаря. -tutorial.moreDrills.text = Вы можете соединить много буров и конвейеров вместе, вот так. -tutorial.deleteBlock.text = Вы можете удалить блоки, щелкнув [orange]правой кнопкой мыши[] на блоке, который вы хотите удалить. Попробуйте удалить этот конвейер. -tutorial.deleteBlockAndroid.text = Вы можете удалить блоки [orange]выбрав перекрестие []в меню режима сноса[orange][] в левом нижнем углу и нажать на блок. Попробуйте удалить этот конвейер. -tutorial.placeTurret.text = Теперь выберите и поместите [yellow]турель[] в [yellow]отмеченную позицию[]. -tutorial.placedTurretAmmo.text = Эта турель теперь принимает [yellow]боеприпасы[] от конвейера. Вы можете видеть, сколько патронов у него есть, посмотрев на зеленую полосу над ней [green][]. -tutorial.turretExplanation.text = Турели автоматически стреляют в ближайшего противника в радиусе действия, если у них достаточно боеприпасов. -tutorial.waves.text = Каждые [yellow]60[] секунд, волна [coral]противников[] будет появляться в определенных местах и будет ​​пытаться уничтожить ядро. -tutorial.coreDestruction.text = Ваша цель - [yellow]защитить ядро​​[]. Если ядро будет ​​уничтожено, то вы [cotal]проиграете[] -tutorial.pausingDesktop.text = Если вам нужен будет перерыв, нажмите кнопку [orange]пауза[] в верхнем левом углу или [orange]пробел[],чтобы приостановить игру. Вы можете выбирать и размещать блоки во время паузы, но не можете перемещаться или стрелять. -tutorial.pausingAndroid.text = Если вам нужен будет перерыв, нажмите кнопку [orange]пауза[] в левом верхнем углу, чтобы приостановить игру. Вы можете по-прежнему размещать выбранные блоки во время паузы. -tutorial.purchaseWeapons.text = Вы можете приобрести новое [yellow]оружие[] для своего меха, открыв меню обновлений в левом нижнем углу. -tutorial.switchWeapons.text = Переключаться между оружием можно, щелкнув на его значок в левом нижнем углу или используя цифры [orange][[1-9][]. -tutorial.spawnWave.text = Сейчас прибудет волна. Уничтожьте их. -tutorial.pumpDesc.text = В более поздних волнах, вы должны использовать [yellow]насосы[] для распределения жидкостей для генераторов или экстракторов. -tutorial.pumpPlace.text = Насосы работают аналогично бурам, за исключением того, что они производят жидкости вместо предметов. Попробуйте поместить насос на [yellow]обозначенную нефть[]. -tutorial.conduitUse.text = Теперь поместите [orange]трубопровод[], ведущий от насоса. -tutorial.conduitUse2.text = И еще немного ... -tutorial.conduitUse3.text = И еще немного ... -tutorial.generator.text = Теперь поместите блок[orange]генератор сжигания[] в конец трубопровода. -tutorial.generatorExplain.text = Этот генератор теперь создаст [yellow]энергию[] из нефти. -tutorial.lasers.text = Энергия распределяется с использованием [yellow]электрических лазеров[]. Поверните и поместите его здесь. -tutorial.laserExplain.text = Теперь генератор передаст энергию в лазерный блок. [yellow]Непрозрачный[] луч означает, что он в настоящее время передает электричество, а [yellow]прозрачный[] луч означает, что он не передает электричество. -tutorial.laserMore.text = Вы можете проверить,какой заряд у блока, наблюдая за [yellow]желтой полосой[] над ним. -tutorial.healingTurret.text = Этот лазер можно использовать для питания [lime]ремонтной турели[]. Поместите её сюда. -tutorial.healingTurretExplain.text = Пока она имеет заряд, эта турель будет [lime]ремонтировать соседние блоки.[] Когда вы играете, убедитесь, что вы имеете такую на своей базе как можно быстрее. -tutorial.smeltery.text = Для многих блоков требуется [orange]сталь[], для этого требуется [orange]плавильный завод[]. Поместите его сюда. -tutorial.smelterySetup.text = Этот завод теперь производит [orange]сталь[] из поступающего железа, используя уголь в качестве топлива. -tutorial.tunnelExplain.text = Также обратите внимание, что предметы проходят через [orange] туннельный блок [] и появляются на другой стороне, проходя через каменный блок. Имейте в виду, что туннели могут проходить только до двух блоков. -tutorial.end.text = На этом обучение закончено! Удачи! -text.keybind.title = Переназначить клавиши -keybind.move_x.name = движение_x -keybind.move_y.name = движение_y -keybind.select.name = выбрать -keybind.break.name = Разрушить -keybind.shoot.name = стрельба -keybind.zoom_hold.name = удержание_зума -keybind.zoom.name = Приблизить -keybind.block_info.name = инфо_о_блоке -keybind.menu.name = Меню -keybind.pause.name = Пауза -keybind.dash.name = Рывок -keybind.chat.name = Чат -keybind.player_list.name = список_игроков -keybind.console.name = консоль -keybind.rotate_alt.name = вращать_alt -keybind.rotate.name = вращать -keybind.weapon_1.name = Оружие_1 -keybind.weapon_2.name = Оружие_2 -keybind.weapon_3.name = Оружие_3 -keybind.weapon_4.name = Оружие_4 -keybind.weapon_5.name = Оружие_5 -keybind.weapon_6.name = Оружие_6 +text.loading=[accent] Загрузка... +text.wave=[orange]Волна {0} +text.wave.waiting=Волна через {0} +text.waiting=Ожидание... +text.enemies={0} Противников +text.enemies.single={0} Противник +text.loadimage=Загрузить изображение +text.saveimage=Сохранить изображение +text.editor.badsize=[orange]Недопустимый формат изображения! [] \nДопустимый формат карты: {0} +text.editor.errorimageload=Ошибка загрузки изображения: [orange] {0} +text.editor.errorimagesave=Ошибка сохранения изображения: [orange] {0} +text.editor.generate=Создать +text.editor.resize=Изменить \nразмер +text.editor.loadmap=Загрузить\nкарту +text.editor.savemap=Сохранить\nкарту +text.editor.loadimage=Загрузить \nизображение +text.editor.saveimage=Сохранить \nизображение +text.editor.unsaved=[scarlet]У вас есть не сохраненные изменения![] \nВы уверены,что хотите выйти? +text.editor.resizemap=Изменить размер карты +text.editor.mapname=Название карты: +text.editor.overwrite=[accent]Внимание! \nЭто перезапишет уже существующую карту. +text.editor.selectmap=Выберите карту для загрузки: +text.width=Ширина: +text.height=Высота: +text.menu=Меню +text.play=Играть +text.load=Загрузить +text.save=Сохранить +text.language.restart=Перезагрузите игру, чтобы настройки языка вступили в силу. +text.settings.language=Язык +text.settings=Настройки +text.tutorial=Обучение +text.editor=Редактор +text.mapeditor=Редактор карт +text.donate=Донат +text.settings.reset=Сбросить по умолчанию +text.settings.controls=Управление +text.settings.game=Игра +text.settings.sound=Звук +text.settings.graphics=Графика +text.upgrades=Улучшения +text.purchased=[LIME]Создан! +text.weapons=Оружие +text.paused=Пауза +text.info.title=[accent]Информация +text.error.title=[crimson]Произошла ошибка +text.error.crashtitle=Произошла ошибка +text.blocks.blockinfo=Информация о блоке +text.blocks.powercapacity=Вместимость энергии +text.blocks.powershot=Энергия / выстрел +text.blocks.size=Размер +text.blocks.liquidcapacity=Вместимость жидкости +text.blocks.maxitemssecond=Макс. Количество предметов / в секунду +text.blocks.powerrange=Диапазон мощности энергии +text.blocks.itemcapacity=Вместимость предметов +text.blocks.inputliquid=Прием жидкости +text.blocks.inputitem=Прием предмета +text.blocks.explosive=Взрывоопасно! +text.blocks.health=Здоровье +text.blocks.inaccuracy=Разброс +text.blocks.shots=Выстрелы +text.blocks.inputcapacity=Вместимость ввода +text.blocks.outputcapacity=Вместимость вывода +setting.difficulty.easy=легко +setting.difficulty.normal=нормально +setting.difficulty.hard=тяжело +setting.difficulty.insane=нереально +setting.difficulty.purge=зачистка +setting.difficulty.name=Сложность +setting.screenshake.name=Дрожание экрана +setting.indicators.name=Индикаторы противников +setting.effects.name=Эффекты на экране +setting.sensitivity.name=Чувствительность контроллера +setting.saveinterval.name=Интервал автосохранения +setting.seconds={0} Секунд +setting.fullscreen.name=Полноэкранный +setting.multithread.name=Многопоточность +setting.fps.name=Показать FPS +setting.vsync.name=Верт. синхронизация +setting.lasers.name=Показывать энергетические лазеры +setting.healthbars.name=Показать полоски здоровья объекта +setting.musicvol.name=Громкость музыки +setting.mutemusic.name=Заглушить музыку +setting.sfxvol.name=Громкость звуковых эффектов +setting.mutesound.name=Заглушить звук +map.maze.name=лабиринт +map.fortress.name=крепость +map.sinkhole.name=раковина +map.caves.name=пещеры +map.volcano.name=вулкан +map.caldera.name=кальдера +map.scorch.name=горение +map.desert.name=пустыня +map.island.name=остров +map.grassland.name=луг +map.tundra.name=тундра +map.spiral.name=спираль +map.tutorial.name=обучение +text.keybind.title=Переназначить клавиши +keybind.move_x.name=движение_x +keybind.move_y.name=движение_y +keybind.select.name=выбрать +keybind.break.name=Разрушить +keybind.shoot.name=стрельба +keybind.zoom_hold.name=удержание_зума +keybind.zoom.name=Приблизить +keybind.block_info.name=инфо_о_блоке +keybind.menu.name=Меню +keybind.pause.name=Пауза +keybind.dash.name=Рывок +keybind.chat.name=Чат +keybind.player_list.name=список_игроков +keybind.console.name=консоль +keybind.rotate_alt.name=вращать_alt +keybind.rotate.name=вращать mode.text.help.title=Описание режимов -mode.waves.name = волны -mode.waves.description = в нормальном режиме. ограниченные ресурсы и автоматические наступающие волны. -mode.sandbox.name = песочница -mode.sandbox.description = бесконечные ресурсы и нет таймера для волн. -mode.freebuild.name = свободная\nстройка +mode.waves.name=волны +mode.waves.description=в нормальном режиме. ограниченные ресурсы и автоматические наступающие волны. +mode.sandbox.name=песочница +mode.sandbox.description=бесконечные ресурсы и нет таймера для волн. +mode.freebuild.name=свободная\nстройка mode.freebuild.description=ограниченные ресурсы и нет таймера для волн. -upgrade.standard.name = стандарт -upgrade.standard.description = Стандартный мех. -upgrade.blaster.name = Бластер -upgrade.blaster.description = Стреляет медленной, слабой пулей. -upgrade.triblaster.name = трибластер -upgrade.triblaster.description = Стреляет 3 пулями в разброс. -upgrade.clustergun.name = Кластерная пушка -upgrade.clustergun.description = Стреляет неточным распространением взрывных гранат. -upgrade.beam.name = Лучевая пушка -upgrade.beam.description = Стреляет пробивающим лазерным луч высокой дальности. -upgrade.vulcan.name = вулкан -upgrade.vulcan.description = Стреляет шквалом быстрых пуль. -upgrade.shockgun.name = шоковая пушка -upgrade.shockgun.description = Стреляет взрывным зарядом заряженной шрапнели. -item.stone.name = камень -item.iron.name = железо -item.coal.name = Уголь -item.steel.name = сталь -item.titanium.name = титан -item.dirium.name = дириум -item.thorium.name = уран -item.sand.name = песок -liquid.water.name = Вода -liquid.plasma.name = Плазма -liquid.lava.name = лава -liquid.oil.name = Нефть -block.weaponfactory.name = оружейный завод -block.weaponfactory.fulldescription=Используется для создания оружия для игрока. Нажмите для использования. Автоматически извлекает ресурсы из ядра. -block.air.name = воздух -block.blockpart.name = часть блока -block.deepwater.name = глубоководье -block.water.name = вода -block.lava.name = лава -block.oil.name = нефть -block.stone.name = Камень -block.blackstone.name = черный камень -block.iron.name = железо -block.coal.name = уголь -block.titanium.name = титан -block.thorium.name = уран -block.dirt.name = земля -block.sand.name = песок -block.ice.name = лед -block.snow.name = снег -block.grass.name = трава -block.sandblock.name = блок песка -block.snowblock.name = блок снега -block.stoneblock.name = блок камня -block.blackstoneblock.name = блок черного камня -block.grassblock.name = блок травы -block.mossblock.name = блок мха -block.shrub.name = кустарник -block.rock.name = валун -block.icerock.name = замерзший валун -block.blackrock.name = черный валун -block.dirtblock.name = блок земли -block.stonewall.name = каменная стена -block.stonewall.fulldescription = Дешевый оборонительный блок. Полезен для защиты ядра и турелей в первых волнах. -block.ironwall.name = железная стена -block.ironwall.fulldescription = Основной защитный блок. Обеспечивает защиту от противников. -block.steelwall.name = стальная стена -block.steelwall.fulldescription = Стандартный защитный блок. адекватная защита от противников. -block.titaniumwall.name = титановая стена -block.titaniumwall.fulldescription = Сильный защитный блок. Обеспечивает защиту от противников. -block.duriumwall.name = стена из дириума -block.duriumwall.fulldescription = Очень прочный защитный блок. Обеспечивает защиту от противников. -block.compositewall.name = композитная стена -block.steelwall-large.name = большая стальная стена -block.steelwall-large.fulldescription = Стандартный защитный блок. Охватывает несколько клеток. -block.titaniumwall-large.name = большая титановая стена -block.titaniumwall-large.fulldescription = Сильный защитный блок. Охватывает несколько клеток. -block.duriumwall-large.name = большая стена из дириума -block.duriumwall-large.fulldescription = Очень сильный защитный блок. Охватывает несколько клеток. -block.titaniumshieldwall.name = экранированная стена -block.titaniumshieldwall.fulldescription = Прочный защитный блок с дополнительным встроенным щитом. Требует энергию. Использует энергию для поглощения вражеских пуль. Для обеспечения энергией этого блока рекомендуется использовать усилители энергии. -block.repairturret.name = ремонтная турель -block.repairturret.fulldescription = Ремонтирует близлежащие поврежденные блоки в радиусе действия. Использует небольшое количество энергии. -block.megarepairturret.name = ремонтная турель II -block.megarepairturret.fulldescription = Ремонтирует близлежащие поврежденные блоки в радиусе действия с приличной скоростью. Использует энергию. -block.shieldgenerator.name = Генератор щита -block.shieldgenerator.fulldescription = Передовой защитный блок. Защищает все блоки в радиусе от атаки. Использует мало энергии когда бездействует, но быстро разряжается при контакте с пулями. -block.door.name = дверь -block.door.fulldescription = Блок, который можно открыть и закрыть, нажав на него. -block.door-large.name = большая дверь -block.door-large.fulldescription = Блок, который можно открыть и закрыть, нажав на него. -block.conduit.name = трубопровод -block.conduit.fulldescription = Основной блок транспортировки жидкости. Работает как конвейер, но с жидкостями. Лучше всего использовать насосы или другие трубопроводы. Может использоваться как мост через жидкости для противников и игроков. -block.pulseconduit.name = импульсный трубопровод -block.pulseconduit.fulldescription = Передовой блок транспортировки жидкости. Перемещает жидкости быстрее и хранит больше, чем стандартные трубопроводы. -block.liquidrouter.name = Маршрутизатор житкостей -block.liquidrouter.fulldescription = Работает аналогично маршрутизатору. Принимает жидкость с одной стороны и выводит ее на другие стороны. Полезно для разделения жидкости из одного трубопровода на несколько других трубопроводов. -block.conveyor.name = конвейер -block.conveyor.fulldescription = Основной транспортный блок. Перемещает предметы вперед и автоматически перекладывает их в турели или в крафтеры. Могут вращаться . Может использоваться как мост через жидкости для противников и игроков. -block.steelconveyor.name = стальной конвейер -block.steelconveyor.fulldescription = Передовой транспортный блок предметов. Перемещает предметы быстрее, чем стандартные конвейеры. -block.poweredconveyor.name = импульсный конвейер -block.poweredconveyor.fulldescription = Лучший транспортный блок. Перемещает предметы быстрее, чем стальные конвейеры. -block.router.name = Маршрутизатор -block.router.fulldescription = Принимает предметы с одного направления и выводит их в 3 других направлениях. Может также хранить определенное количество предметов. Используется для разделения материалов с одного бура на несколько турелей -block.junction.name = Перекресток -block.junction.fulldescription = Действует как мост для двух конвейерных лент. Полезно в ситуациях с двумя различными конвейерами, несущими разные материалы в разные места. -block.conveyortunnel.name = конвейерный туннель -block.conveyortunnel.fulldescription = Перемещает предмет под блоками. Чтобы использовать, поместите один туннель, ведущий в блок, который должен быть туннелирован, и один на другой стороне. Убедитесь, что оба туннеля обращены к противоположным направлениям, которые относятся к блокам, которые они принимают или выводят. -block.liquidjunction.name = Перекресток для жидкостей -block.liquidjunction.fulldescription = Действует как мост для двух пересекающихся трубопроводов. Полезно в ситуациях с двумя различными каналами, перемещающими различные жидкости в разные места. -block.liquiditemjunction.name = Распределитель жидкостей и предметов -block.liquiditemjunction.fulldescription = Действует как мост для пересекающихся трубопроводов и конвейеров. -block.powerbooster.name = усилитель энергии -block.powerbooster.fulldescription = Распределяет электричество всем блокам в пределах своего радиуса. -block.powerlaser.name = Энергетический лазер -block.powerlaser.fulldescription = Создает лазер, который передает питание блоку перед ним. Не генерирует никакой энергии. Лучше всего использовать с генераторами или другими лазерами. -block.powerlaserrouter.name = лазерный маршрутизатор -block.powerlaserrouter.fulldescription = Лазер, который одновременно передает электричество в три направления. Полезно в тех ситуациях, когда требуется питание нескольким блокам от одного генератора. -block.powerlasercorner.name = лазерный угол -block.powerlasercorner.fulldescription = Лазер, распределяющий энергию сразу на два направления. Полезно в тех ситуациях, когда требуется питание нескольким блокам от одного генератора, а маршрутизатор не годится. -block.teleporter.name = телепорт -block.teleporter.fulldescription = Улучшенный транспортный блок предметов. Телепортеры передают предметы в другие телепорты одного цвета. Ничего не происходит, если нет телепортеров одного цвета. Если несколько телепортеров имеют один и тот же цвет, выбирается случайный. Использует энергия. Нажмите, чтобы изменить цвет. -block.sorter.name = сортировщик -block.sorter.fulldescription = Сортирует предмет по типу материала. Материал для приема указывается цветом в блоке. Все предметы, соответствующие материалу сортировки, выводятся вперед, все остальное выводится влево и вправо. -block.core.name = Ядро -block.pump.name = Насос -block.pump.fulldescription = Качают жидкости из блока источнка - обычно вода, лава или нефть. Выводит жидкость в соседние трубопроводы. -block.fluxpump.name = Флюсовый насос -block.fluxpump.fulldescription = Передовая версия насоса. Хранит больше жидкости и качает быстрее. -block.smelter.name = Плавильный завод -block.smelter.fulldescription = Основной блок крафтер. При вводе 1 х железа и 1 х угля выдается одна сталь. -block.crucible.name = Тигель -block.crucible.fulldescription = Продвинутый блок крафтер. При вводе 1х титана и 1х стали выдается один дириум. -block.coalpurifier.name = Экстрактор угля -block.coalpurifier.fulldescription = Стандартный экстрактор. Выдает уголь, когда подается большое количество воды и камня. -block.titaniumpurifier.name = Экстрактор титана -block.titaniumpurifier.fulldescription = Стандартный экстрактор. Выдает титан при подаче большого количества воды и железа. -block.oilrefinery.name = Нефтеперерабатывающий Завод -block.oilrefinery.fulldescription = Перерабатывает большое количество нефти в уголь. Полезно для заправки турелей использующих уголь, когда на карте дефицит угля. -block.stoneformer.name = Формировщик камня -block.stoneformer.fulldescription = Охлаждает жидкую лаву, делая из него камень. Полезен для производства большого количества камней для ​угольного очистителя -block.lavasmelter.name = лавовый плавильный завод -block.lavasmelter.fulldescription = Использует лаву для переработки железа в сталь. Альтернатива плавильным заводам. Полезно в ситуациях, когда угля мало. -block.stonedrill.name = каменный бур -block.stonedrill.fulldescription = Важный бур. Когда он помещается на каменную клетку, медленно, бесконечно добывает камень. -block.irondrill.name = Железный бур -block.irondrill.fulldescription = Основной бур. При размещении на клетке с железной рудой, выдает железо медленным темпом на неопределенный срок. -block.coaldrill.name = угольный бур -block.coaldrill.fulldescription = Основной бур. При размещении на клетке с угольной рудой происходит медленный темп добычи угля на неопределенный срок. -block.thoriumdrill.name = урановый бур -block.thoriumdrill.fulldescription = Передовой бур. При размещении на клетке с урановой рудой выдает уран медленным темпом на неопределенный срок. -block.titaniumdrill.name = титановый бур -block.titaniumdrill.fulldescription = Продвинутый бур. При размещении на клетках с титановой рудой выводится титан медленным темпом на неопределенный срок. -block.omnidrill.name = Адаптивный бур -block.omnidrill.fulldescription = Идеальный бур. Будет добывать любую руду на которой стоит с безумным темпом\n -block.coalgenerator.name = угольный генератор -block.coalgenerator.fulldescription = Важный генератор. Генерирует энергию из угля. Выводит энергию в качестве лазеров на 4 стороны. -block.thermalgenerator.name = термальный генератор -block.thermalgenerator.fulldescription = Генерирует энергию из лавы. Выводит электричество в качестве лазеров на 4 стороны. -block.combustiongenerator.name = генератор внутреннего сгорания -block.combustiongenerator.fulldescription = Генерирует энергию из нефти. Выводит энергию в качестве лазеров на 4 стороны. -block.rtgenerator.name = Генератор RTG -block.rtgenerator.fulldescription = Генерирует небольшое количество энергии из распада радиоактивного урана. Выводит энергию в качестве лазеров на 4 стороны. -block.nuclearreactor.name = ядерный реактор -block.nuclearreactor.fulldescription = Передовая версия генератора RTG и идеальный источник энергии. Генерирует энергию из урана. Требуется постоянное водяное охлаждение.Крайне взрывоопасен; сильно взорвётся при подаче недостаточного количества хладагента. -block.turret.name = Турель -block.turret.fulldescription = Базовая, дешевая турель. Использует камень для боеприпасов. Имеет немного больше диапазон, чем двойная турель. -block.doubleturret.name = двойная турель -block.doubleturret.fulldescription = Немного более мощная версия турели. Использует камень для боеприпасов. Значительно больший урон, но имеет более низкий диапазон. Выстреливает двумя пулями. -block.machineturret.name = Турель Гатлинга -block.machineturret.fulldescription = Стандартная универсальная турель. Использует железо для боеприпасов. Обладает быстрой скоростью выстрелов с приличным уроном. -block.shotgunturret.name = разветвленная турель\n -block.shotgunturret.fulldescription = Стандартная турель. Использует железо для боеприпасов. Стреляет в разброс 7 пулями. Маленький диапазон, но более высокий уровень урона по сравнению с турелью Гатлинга. -block.flameturret.name = Огнемётная турель\n -block.flameturret.fulldescription = Продвинутая турель для защиты на близком расстоянии. Использует уголь для боеприпасов. Имеет очень маленький диапазон, но очень высокий урон. Хорошо подходит на близких расстояниях. Рекомендуется использовать со стенами. -block.sniperturret.name = Турель-рельсотрон -block.sniperturret.fulldescription = Продвинутая дальнобойная турель. Использует сталь для боеприпасов. Очень высокий урон, но низкая скорость стрельбы. Дорога в использовании, но может быть помещена далеко от вражеских линий из-за её дальности. -block.mortarturret.name = Зенитная турель -block.mortarturret.fulldescription = Продвинутая турель с уроном по зоне. Использует уголь для боеприпасов. Очень низкая скорость стрельбы и пуль, но очень высокий урон по одной цели и зоне. Полезен для больших толп врагов. -block.laserturret.name = лазерная турель -block.laserturret.fulldescription = Продвинутая турель. Использует энергию. Хорошая , универсальная турель средней дальности. Атакует только одну цель. Никогда не промахивается. -block.waveturret.name = Тесла-турель -block.waveturret.fulldescription = Продвинутая многоцелевая турель. Использует энергию. Средняя дальность. Никогда не промахивается. В среднем, может нанести небольшой урон, но он может поразить нескольких противников одновременно с помощью цепной молнии. -block.plasmaturret.name = плазменная турель -block.plasmaturret.fulldescription = Высокотехнологичная версия огнеметной турели. Использует уголь в качестве боеприпасов. Очень высокий урон, дальность между маленькой и средней. -block.chainturret.name = Пулемётная турель -block.chainturret.fulldescription = Самая лучшая, скорострельная турель. Использует уран для боеприпасов. Стреляет большими снарядами с высокой скорострельностью. Средняя дальность. Охватывает несколько клеток. Чрезвычайно прочная. -block.titancannon.name = Пушка-титан -block.titancannon.fulldescription = Самая лучшая, дальнобойная турель. Использует уран как боеприпасы. Стреляет большими снарядами с уроном по зоне со средней скоростью стрельбы. Большая дальность. Охватывает несколько клеток. Чрезвычайно прочная. -block.playerspawn.name = Точка появления игрока -block.enemyspawn.name = Точка появления врага +item.stone.name=камень +item.coal.name=Уголь +item.titanium.name=титан +item.thorium.name=уран +item.sand.name=песок +liquid.water.name=Вода +liquid.lava.name=лава +liquid.oil.name=Нефть +block.door.name=дверь +block.door-large.name=большая дверь +block.conduit.name=трубопровод +block.pulseconduit.name=импульсный трубопровод +block.liquidrouter.name=Маршрутизатор житкостей +block.conveyor.name=конвейер +block.router.name=Маршрутизатор +block.junction.name=Перекресток +block.liquidjunction.name=Перекресток для жидкостей +block.sorter.name=сортировщик +block.smelter.name=Плавильный завод +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index 814f36c6e0..b8006f0edb 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -1,551 +1,495 @@ -text.about = [ROYAL] Anuken tarafından oluşturuldu [] - [SKY] anukendev@gmail.com [] Aslen [turuncu] GDL [] Metal Monstrosity Jam. Kredi: - [SARI] ile yapılan SFX bfxr [] - [YEŞİL] RoccoW tarafından yapılan müzik [] / [kireç] bulunan FreeMusicArchive.org [] Özel teşekkürler: - [mercan] MitchellFJN []: Kapsamlı oyun testi ve geri bildirim - [sky] Luxray5474 []: wiki çalışması, kod katkıları - [kireç] Epowerj []: kod sistemi yapılandırması, icon - itch.io ve Google Play'deki tüm beta test kullanıcıları\n -text.credits = Yapımcılar -text.discord = Mindustry Discord'una katılın! -text.changes = [SCARLET] Dikkat! [] Bazı önemli oyun mekanikleri değişti. - [Aksanın] teletaşıyıcı [] şimdi artık gücü kullanıyor. - [accent] dökümcü [] ve [accent] pota [] artık bir maksimum ürün kapasitesine sahip. - [Aksan] pota [] artık yakıt olarak kömür gerektiriyor. -text.link.discord.description = Resmi Mindustry Discord iletişim kanalı -text.link.github.description = Oyunun kaynak kodu -text.link.dev-builds.description = Geliştirme altında olan sürüm -text.link.trello.description = Planlanan özellikler için resmi Trello Bülteni -text.link.itch.io.description = PC yüklemeleri ve web sürümü ile itch.io sayfası -text.link.google-play.description = Google Play mağaza sayfası -text.link.wiki.description = Resmi Mindustry Wikipedi'si -text.linkfail = Bağlantı açılamadı! URL, yazı tahtanıza kopyalandı. -text.editor.web = Web sürümü editörü desteklemiyor! Editörü kullanmak için oyunu indirin. -text.multiplayer.web = Oyunun bu sürümü çok oyunculuyu desteklemiyor! Tarayıcınızdan çok oyunculu oynamak için, itch.io sayfasındaki \"çok oyunculu web sürümü\" bağlantısını kullanın. -text.gameover = Çekirdek yok edildi. -text.highscore = [SARI] Yeni yüksek puan! -text.lasted = Dalgaya kadar sürdün -text.level.highscore = Yüksek Puan: [accent] {0} -text.level.delete.title = Silmeyi onaylayın -text.level.delete = \"[Orange] {0} \" Haritayı silmek istediğinizden emin misiniz? -text.level.select = Seviye Seç -text.level.mode = Oyun Modu -text.savegame = Oyunu Kaydet -text.loadgame = Oyunu yükle -text.joingame = Oyuna katıl -text.newgame = Yeni Oyun -text.quit = Çık -text.about.button = Hakkında -text.name = Adı: -text.public = Herkese açık -text.players = 1090 oyuncu çevrimiçi -text.server.player.host = Sunucu -text.players.single = {0} Oyuncu Çevrimiçi -text.server.mismatch = Paket hatası: olası istemci / sunucu sürümü uyuşmazlığı. Siz ve ev sahibi Mindustry'nin en son sürümüne sahip olduğunuzdan emin olun! -text.server.closing = [accent] Sunucu kapatılıyor ... -text.server.kicked.kick = Sunucudan kovuldun! -text.server.kicked.invalidPassword = Geçersiz şifre! -text.server.kicked.clientOutdated = Oyun sürümünüz geçerli değil. Oyununu güncelleyin! -text.server.kicked.serverOutdated = Eski sunucu! Ev sahibinden güncellemesini isteyin! -text.server.kicked.banned = Bu sunucudan yasaklandınız. -text.server.kicked.recentKick = Son zamanlarda tekmelendin. Tekrar bağlanmadan önce bekleyin. -text.server.connected = {0} katıldı. -text.server.disconnected = {0} bağlantısı kesildi. -text.nohost = Özel bir haritada sunucuyu barındıramıyor! -text.host.info = [Vurgu] ana bilgisayarı [] düğmesi, [657] [65] [65] ve [65] [6568] bağlantı noktalarında bir sunucuyu barındırır. [] Aynı [LIGHT_GRAY] wifi veya yerel ağ [] üzerindeki herkes sunucunuzu sunucularında görebilir. liste. Kişilerin IP tarafından herhangi bir yerden bağlanabilmesini istiyorsanız [vurgu] bağlantı noktası iletme [] gereklidir. [LIGHT_GRAY] Not: Birisi LAN oyununuza bağlanırken sorun yaşıyorsa, güvenlik duvarı ayarlarınızda Mindustry'e yerel ağınıza erişebildiğinizden emin olun. -text.join.info = Burada, bağlanmak için yerel ağ [] sunucularına bağlanmak ya da [aksan] sunucularını bulmak için bir [vurgu] sunucunun IP [] girebilirsiniz. Hem LAN hem de WAN çok oyunculu desteklenir. [LIGHT_GRAY] Not: Otomatik bir global sunucu listesi yoktur; Birisine IP ile bağlanmak isterseniz, ana bilgisayardan kendi IP adreslerini sormanız gerekir. -text.hostserver = Oyunu Sun -text.host = evsahibi -text.hosting = [accent] Sunucu açılıyor ... -text.hosts.refresh = Yenile -text.hosts.discovering = LAN oyunlarını keşfetme -text.server.refreshing = Canlandırıcı sunucu -text.hosts.none = [lightgray] Hayır LAN oyunları bulundu! -text.host.invalid = [scarlet] Ana bilgisayara bağlanılamıyor. -text.server.friendlyfire = Dost ateşi -text.trace = Oyuncuyu Takip Et -text.trace.playername = Oyuncu adı: [accent] {0} -text.trace.ip = IP: [vurgu] {0} -text.trace.id = Benzersiz kimlik: [accent] {0} -text.trace.android = Android : [accent] {0} -text.trace.modclient = Özel Alıcı: [accent] {0} -text.trace.totalblocksbroken = Toplam kırık blok: [accent] {0} -text.trace.structureblocksbroken = Kırılan yapı blokları: [accent] {0} -text.trace.lastblockbroken = Kırılan son blok: [accent] {0} -text.trace.totalblocksplaced = Toplam blok yerleştirildi: [accent] {0} -text.trace.lastblockplaced = Konulan son blok: [accent] {0} -text.invalidid = Geçersiz alıcı kimliği! Bir hata raporu gönderin. -text.server.bans = yasaklar -text.server.bans.none = Yasaklanmış oyuncu bulunamadı! -text.server.admins = Yöneticiler -text.server.admins.none = Yönetici bulunamadı! -text.server.add = Sunucu ekle -text.server.delete = Bu sunucuyu silmek istediğinizden emin misiniz? -text.server.hostname = Sun -text.server.edit = Sunucuyu Düzenle -text.server.outdated = [crimson] Eski Sunucu! -text.server.outdated.client = [crimson] Eski Alıcı! -text.server.version = [lightgray] Sürüm: {0} -text.server.custombuild = [sarı] Özel Yapım -text.confirmban = Bu oyuncuyu yasaklamak istediğinizden emin misiniz? -text.confirmunban = Bu oyuncunun yasağını kaldırmak istediğinden emin misin? -text.confirmadmin = Bu oyuncunun yönetici yapmak istediğinden emin misin? -text.confirmunadmin = Bu oyuncudan yönetici durumunu kaldırmak istediğinizden emin misiniz? -text.joingame.byip = IP ile Katılın ... -text.joingame.title = Oyuna katılmak -text.joingame.ip = IP: -text.disconnect = Bağlantı Kesildi -text.disconnect.data = Dünya verileri yüklenemedi! -text.connecting = [Vurgu] bağlanıyor ... -text.connecting.data = [accent] Dünya verileri yükleniyor ... -text.connectfail = [crimson] Sunucuya bağlanılamadı: [orange] {0} -text.server.port = Liman -text.server.addressinuse = Adres çoktan kullanımda! -text.server.invalidport = Bağlantı noktası numarası geçersiz. -text.server.error = [crimson] Sunucu barındırma hatası: [orange] {0} -text.tutorial.back = <Önceki -text.tutorial.next = İleri > -text.save.new = 6349,Yeni Kayıt -text.save.overwrite = Bu kayıt yuvasının üzerine yazmak istediğinizden emin misiniz? -text.overwrite = Üzerine Yaz -text.save.none = Hiçbir kayıt bulunamadı! -text.saveload = [Vurgu] Kaydediliyor ... -text.savefail = Oyun kaydedilemedi! -text.save.delete.confirm = Bu kaydı silmek istediğinizden emin misiniz? -text.save.delete = Sil -text.save.export = Dışa Aktar -text.save.import.invalid = [turuncu] Bu kayıt geçersiz! -text.save.import.fail = [crimson] Kayıt oyuna aktarılamadı : [orange] {0} -text.save.export.fail = [crimson] Kayıt dışa aktarılamadı: [orange] {0} -text.save.import = İçe Aktar -text.save.newslot = İsmi kaydet: -text.save.rename = Yeniden Adlandır -text.save.rename.text = Yeni İsim: -text.selectslot = Bir kayıt seçin. -text.slot = [accent] Yuva {0} -text.save.corrupted = [orange] Kayıt dosyası bozuk veya geçersiz! -text.empty = -text.on = Açık -text.off = Kapalı -text.save.autosave = Otomatik kaydetme: {0} -text.save.map = harita -text.save.wave = Dalga -text.save.difficulty = zorluk -text.save.date = Son Kaydedilen: {0} -text.confirm = Onayla -text.delete = Sil -text.ok = Tamam -text.open = Açık -text.cancel = İptal -text.openlink = Linki aç -text.copylink = Bağlantıyı kopyala -text.back = Geri -text.quit.confirm = Çıkmak istediğinden emin misin? -text.changelog.title = Değişiklik listesi -text.changelog.loading = Değişiklik listesi yükleniyor -text.changelog.error.android = [turuncu] Android'da olan hata nedeniyle değişiklik listesi görüntülenemiyor. -text.changelog.error = [scarlet] Değişiklik listesi alma hatası! İnternet bağlantınızı kontrol edin. -text.changelog.current = [sarı] [[Güncel versiyon] -text.changelog.latest = [turuncu] [[Son sürüm] -text.loading = [Vurgu] Yükleniyor ... -text.wave = [turuncu] Dalga {0} -text.wave.waiting = {0} içinde dalga -text.waiting = Bekleniyor -text.enemies = {0} Düşmanlar -text.enemies.single = {0} Düşman -text.loadimage = Resmi yükle -text.saveimage = Resmi Kaydet -text.oregen = Maden Üretimi -text.editor.badsize = [orange] Resim boyutları geçersiz! [] Geçerli harita boyutları: {0} -text.editor.errorimageload = Resim dosyası yüklenirken hata oluştu: [orange] {0} -text.editor.errorimagesave = Resim dosyası kaydedilirken hata oluştu: [orange] {0} -text.editor.generate = Üretmek -text.editor.resize = Yeniden Boyutlandırma -text.editor.loadmap = Harita Yükle -text.editor.savemap = Harita Kaydet -text.editor.loadimage = Resmi yükle -text.editor.saveimage = Resmi Kaydet -text.editor.unsaved = [scarlet] Kaydedilmemiş değişiklikleriniz var! [] Çıkmak istediğinizden emin misiniz? -text.editor.brushsize = Fırça boyutu: {0} -text.editor.noplayerspawn = Bu haritanın oyuncu spawnpoint'i yok! -text.editor.manyplayerspawns = Haritalar, birden fazla oyuncu spawnpoint'e sahip olamaz! -text.editor.manyenemyspawns = {0} düşman spawnpoint {0}'den daha fazlası olamaz! -text.editor.resizemap = Haritayı Yeniden Boyutlandır -text.editor.resizebig = [Kızıl] Uyarı! [] 256'dan büyük haritalar yavaş ve dengesiz olabilir. -text.editor.mapname = Harita Adı -text.editor.overwrite = [Vurgu] Uyarı! Bu mevcut bir haritanın üzerine yazar. -text.editor.failoverwrite = [crimson] Varsayılan haritanın üzerine yazılamıyor! -text.editor.selectmap = Yüklenecek bir harita seçin: -text.width = Genişliği: -text.height = Boy: -text.randomize = Rasgele seçmek -text.apply = Uygula -text.update = Güncelle -text.menu = Menü -text.play = Oyna -text.load = Yükle -text.save = Kaydet -text.language.restart = Lütfen dil ayarlarının etkili olması için oyununuzu yeniden başlatın. -text.settings.language = Dil -text.settings = Ayarlar -text.tutorial = Eğitim -text.editor = Editör -text.mapeditor = Harita Editörü -text.donate = Bağışlamak -text.settings.reset = Varsayılanlara Dön -text.settings.controls = kontroller -text.settings.game = Oyun -text.settings.sound = Ses -text.settings.graphics = Grafik -text.upgrades = Geliştirmeler -text.purchased = [KİREÇ] Yap၊ld၊ -text.weapons = Silahlar -text.paused = Duraklatıldı -text.respawn = Saniye içinde yeniden doğacaksınız. -text.info.title = [Vurgu] Bilgi -text.error.title = [crimson] Bir hata oluştu -text.error.crashmessage = [SCARLET] Bir kilitlenme meydana getiren beklenmeyen bir hata oluştu. [] Lütfen geliştiriciye bu hatanın gerçekleştiği koşulları bildirin: [ORANGE] anukendev@gmail.com [] -text.error.crashtitle = Bir hata oluştu -text.mode.break = Ara verme modu: {0} -text.mode.place = Döşeme modu: {0} -placemode.hold.name = hat -placemode.areadelete.name = alan -placemode.touchdelete.name = dokun -placemode.holddelete.name = tut -placemode.none.name = Yok -placemode.touch.name = dokun -placemode.cursor.name = İmleç -text.blocks.extrainfo = [accent] fazladan blok bilgisi: -text.blocks.blockinfo = Blok Bilgisi -text.blocks.powercapacity = Güç kapasitesi -text.blocks.powershot = Güç / atış -text.blocks.powersecond = Güç / saniye -text.blocks.powerdraindamage = Güç tahliye / hasar -text.blocks.shieldradius = Kalkan Yarıçapı -text.blocks.itemspeedsecond = Ürün Hız / saniye -text.blocks.range = Menzil -text.blocks.size = Boyut -text.blocks.powerliquid = Güç / Sıvı -text.blocks.maxliquidsecond = Maksimum sıvı / saniye -text.blocks.liquidcapacity = Sıvı kapasitesi -text.blocks.liquidsecond = Sıvı / saniye -text.blocks.damageshot = Zarar / atış -text.blocks.ammocapacity = Mermi kapasitesi -text.blocks.ammo = Cephane: -text.blocks.ammoitem = Cephane / öğe -text.blocks.maxitemssecond = Maksimum öğe / saniye -text.blocks.powerrange = Güç aralığı -text.blocks.lasertilerange = Lazer karo aralığı -text.blocks.capacity = Kapasite -text.blocks.itemcapacity = Ürün kapasitesi -text.blocks.maxpowergenerationsecond = Maksimum Güç Üretimi / saniye -text.blocks.powergenerationsecond = Güç Üretimi / saniye -text.blocks.generationsecondsitem = Nesil Saniye / öğe -text.blocks.input = giriş -text.blocks.inputliquid = Giriş sıvı -text.blocks.inputitem = Giriş öğesi -text.blocks.output = Çıktı -text.blocks.secondsitem = Saniye / öğe -text.blocks.maxpowertransfersecond = Maksimum güç aktarımı / saniye -text.blocks.explosive = Çok patlayıcı! -text.blocks.repairssecond = Tamir / saniye -text.blocks.health = Can -text.blocks.inaccuracy = yanlışlık -text.blocks.shots = atışlar -text.blocks.shotssecond = Çekim / saniye -text.blocks.fuel = Yakıt -text.blocks.fuelduration = Yakıt Süresi -text.blocks.maxoutputsecond = Maksimum çıkış / saniye -text.blocks.inputcapacity = Giriş kapasitesi -text.blocks.outputcapacity = Çıkış kapasitesi -text.blocks.poweritem = Güç / Ürün -text.placemode = Yer Modu -text.breakmode = Mola modu -text.health = sağlık -setting.difficulty.easy = kolay -setting.difficulty.normal = orta -setting.difficulty.hard = zor -setting.difficulty.insane = deli -setting.difficulty.purge = tasfiye -setting.difficulty.name = Zorluk: -setting.screenshake.name = Ekran Sallamak -setting.smoothcam.name = Pürüzsüz kamera -setting.indicators.name = Düşman Göstergeleri -setting.effects.name = Görüntü Efektleri -setting.sensitivity.name = Denetleyici hassasiyeti -setting.saveinterval.name = Otomatik Kaydetme Aralığı -setting.seconds = saniye -setting.fullscreen.name = Tam ekran -setting.multithread.name = Çok iş parçacığı -setting.fps.name = Saniyede ... Kare göstermek -setting.vsync.name = VSync -setting.lasers.name = Güç Lazerleri Göster -setting.healthbars.name = Varlık Sağlık çubuklarını göster -setting.pixelate.name = Piksel Ekran -setting.musicvol.name = Müzik sesi -setting.mutemusic.name = Müziği Kapat -setting.sfxvol.name = SFX Hacmi -setting.mutesound.name = Sesi kapat -map.maze.name = Labirent -map.fortress.name = Kale -map.sinkhole.name = düden -map.caves.name = mağaralar -map.volcano.name = volkan -map.caldera.name = kaldera -map.scorch.name = alazlamak -map.desert.name = çöl -map.island.name = ada -map.grassland.name = Çayır -map.tundra.name = tundra -map.spiral.name = sarmal -map.tutorial.name = Eğitim -tutorial.intro.text = [sarı] Eğiticiye hoşgeldiniz. [] Başlamak için 'ileri' ye basın. -tutorial.moveDesktop.text = Taşımak için [turuncu] [[WASD] [] tuşlarını kullanın. Destek için [turuncu] shift [] tuşunu basılı tutun. Yakınlaştırmak veya uzaklaştırmak için [turuncu] kaydırma tekerini [] kullanırken [turuncu] CTRL [] tuşunu basılı tutun. -tutorial.shoot.text = Hedeflemek için farenizi kullanın, [turuncu] sol fare tuşunu [] vurun. [Sarı] hedef [] üzerinde çalışmayı deneyin. -tutorial.moveAndroid.text = Görünümü kaydırmak için, bir parmağınızı ekran boyunca sürükleyin. Yakınlaştırmak veya uzaklaştırmak için sıkıştırın ve sürükleyin. -tutorial.placeSelect.text = Sağ alttaki blok menüsünden [sarı] bir konveyör [] seçmeyi deneyin. -tutorial.placeConveyorDesktop.text = [Turuncu] [[scrollwheel] [] tuşunu kullanarak konveyörü [turuncu] ileriye [] getirin ve [turuncu] [[sol fare tuşu] [] düğmesini kullanarak [sarı] işaretli konuma [] yerleştirin. -tutorial.placeConveyorAndroid.text = [Turuncu] [[döndürme düğmesi] [] düğmesini kullanarak konveyörü [turuncu] ileriye [] doğru döndürün, bir parmağınızla konumuna sürükleyin, ardından [turuncu] kullanarak [sarı] işaretli konuma [] yerleştirin [[onay işareti][]. -tutorial.placeConveyorAndroidInfo.text = Alternatif olarak, [turuncu] [[dokunma modu] [] moduna geçmek için sol alt taraftaki artı simgesini ve ekrana dokunarak blokları yerleştirebilirsiniz. Dokunmatik modda, bloklar soldaki ok ile döndürülebilir. Denemek için [sarı] sonraki [] tuşuna basın. -tutorial.placeDrill.text = Şimdi, işaretlenmiş konuma bir [sarı] taş matkap [] seçin ve yerleştirin. -tutorial.blockInfo.text = Bir blok hakkında daha fazla bilgi edinmek isterseniz, açıklamayı okumak için sağ üstteki [turuncu] soru işaretine [] dokunabilirsiniz. -tutorial.deselectDesktop.text = [Turuncu] [[sağ fare tuşu] [] kullanarak bir bloğu kaldırabilirsiniz. -tutorial.deselectAndroid.text = [Turuncu] X [] düğmesine basarak bir bloğun seçimini kaldırabilirsiniz. -tutorial.drillPlaced.text = Matkap şimdi [sarı] taş üretecek, [] konveyör üzerine çıkacak, daha sonra [sarı] çekirdeğe [] hareket ettirilecektir. -tutorial.drillInfo.text = Farklı cevherlerin farklı matkaplara ihtiyacı vardır. Taş taş matkaplar gerektirir, demir demir matkaplar gerektirir, vb. -tutorial.drillPlaced2.text = Öğeleri çekirdeğe taşımak, onları sol üstteki [sarı] öğe envanterinize [] yerleştirir. Yerleştirme blokları, envanterinizdeki öğeleri kullanır. -tutorial.moreDrills.text = Birçok matkap ve konveyörü birbirine bağlayabilirsiniz. -tutorial.deleteBlock.text = Silmek istediğiniz blokta [turuncu] sağ fare düğmesine [] tıklayarak blokları silebilirsiniz. Bu konveyörü silmeyi deneyin. -tutorial.deleteBlockAndroid.text = Alt soldaki [turuncu] kesme modu menüsünde [] artı işaretini [] seçerek ve bir bloka dokunarak blokları [turuncu] ile silebilirsiniz. Bu konveyörü silmeyi deneyin. -tutorial.placeTurret.text = Şimdi, [sarı] işaretli konuma [] [sarı] bir taret [] seçin ve yerleştirin. -tutorial.placedTurretAmmo.text = Bu taret artık konveyör [sarı] mermiyi [] kabul edecektir. Üzerinde gezdirerek ne kadar cephane olduğunu ve yeşil renkli [[yeşil] çubuğunu [] kontrol ederek görebilirsiniz. -tutorial.turretExplanation.text = Taretler, yeterli mermiye sahip oldukları sürece otomatik olarak en yakın düşmana ateş ederler. -tutorial.waves.text = Her [sarı] 60 [] saniyede, [mercan] düşmanlardan oluşan bir dalga [] belirli yerlerde doğacak ve çekirdeği yok etmeye çalışacaktır. -tutorial.coreDestruction.text = Hedefiniz [sarı] çekirdeği [] savunmaktır. Çekirdek yok edilirse, [mercan] oyunu kaybedersiniz []. -tutorial.pausingDesktop.text = Bir ara vermeniz gerekiyorsa, oyunu duraklatmak için sol üstteki [turuncu] duraklat [] düğmesine veya [turuncu] boşluk [] tuşuna basın. Duraklatılırken blokları seçebilir ve yerleştirebilirsiniz, ancak hareket edemez veya ateş edemezsiniz. -tutorial.pausingAndroid.text = Bir ara vermeniz gerekirse, oyunu duraklatmak için sol üstteki [turuncu] duraklatma düğmesine [] basın. Duraklatılırken hala blokları kırıp yerleştirebilirsiniz. -tutorial.purchaseWeapons.text = Alt soldaki yükseltme menüsünü açarak, makineniz için yeni [sarı] silahlar [] satın alabilirsiniz. -tutorial.switchWeapons.text = Silahları, sol alt taraftaki simgesini tıklayarak veya sayıları [turuncu] [[1-9] [] kullanarak değiştirebilirsiniz. -tutorial.spawnWave.text = İşte şimdi bir dalga geliyor. Onları yok et. -tutorial.pumpDesc.text = Daha sonraki dalgalarda, jeneratörler veya aspiratörler için sıvı dağıtmak için [sarı] pompaları [] kullanmanız gerekebilir. -tutorial.pumpPlace.text = Pompalar, matkaplar yerine benzer şekilde çalışırlar; [Sarı] belirlenmiş yağa [] bir pompa yerleştirmeyi deneyin. -tutorial.conduitUse.text = Şimdi pompadan önde giden bir [turuncu] kablo kanalı [] yerleştirin. -tutorial.conduitUse2.text = Ve birkaç tane daha ... -tutorial.conduitUse3.text = Ve birkaç tane daha ... -tutorial.generator.text = Şimdi, kanalın ucunda bir [turuncu] yanma jeneratörü [] bloğu yerleştirin. -tutorial.generatorExplain.text = Bu jeneratör şimdi yağdan [sarı] güç [] oluşturacaktır. -tutorial.lasers.text = Güç [sarı] güç lazerleri [] kullanılarak dağıtılır. Döndür ve buraya bir tane yerleştir. -tutorial.laserExplain.text = Jeneratör şimdi gücü lazer bloğuna taşıyacaktır. Bir [sarı] opak [] ışını, şu anda gücü iletmekte olduğu anlamına gelir ve [sarı] saydam [] ışını, bunun olmadığı anlamına gelir. -tutorial.laserMore.text = Bir bloğun üzerine geldiğinde ne kadar gç olduğunu ve üst taraftaki [sarı] sarı çubuğu [] kontrol ederek kontrol edebilirsiniz. -tutorial.healingTurret.text = Bu lazer bir [kireç] onarım tareti [] için kullanılabilir. Bir tane buraya yerleştirin. -tutorial.healingTurretExplain.text = Gücü olduğu sürece, bu taret yakındaki blokları tamir eder. [] en yakın zamanda bu bloku temin edin! -tutorial.smeltery.text = Pek çok blok, [turuncu] yapılabilmesi için çelik gerektirir ve bu da [turuncu] bir dökümcünün [] yapılmasını gerektirir. Bir tane buraya yerleştirin. -tutorial.smelterySetup.text = Bu dökümcü kömürü yakıt olarak kullanarak, demirden [turuncu] çelik [] üretecek. -tutorial.tunnelExplain.text = Ayrıca, eşyaların bir [turuncu] tünel bloğundan [] geçtiğini ve taş bloktan geçerek diğer tarafta ortaya çıktığını unutmayın. Tünellerin yalnızca 2 bloğa kadar gidebileceğini unutmayın. -tutorial.end.text = Ve bu dersi bitirir! İyi şanslar! -text.keybind.title = Tuşları yeniden ayarla -keybind.move_x.name = sağ / sol -keybind.move_y.name = yukarı / aşağı -keybind.select.name = seçmek -keybind.break.name = kırmak -keybind.shoot.name = ateş etme -keybind.zoom_hold.name = tut ve büyüt -keybind.zoom.name = Yakınlaştır -keybind.block_info.name = blok bilgisi -keybind.menu.name = menü -keybind.pause.name = duraklatma -keybind.dash.name = tire -keybind.chat.name = Sohbet -keybind.player_list.name = oyuncu listesi -keybind.console.name = KONTROL MASASI -keybind.rotate_alt.name = rotate_alt -keybind.rotate.name = Döndür -keybind.weapon_1.name = weapon_1 -keybind.weapon_2.name = weapon_2 -keybind.weapon_3.name = weapon_3 -keybind.weapon_4.name = weapon_4 -keybind.weapon_5.name = weapon_5 -keybind.weapon_6.name = weapon_6 -mode.text.help.title = Modların açıklaması -mode.waves.name = dalgalar -mode.waves.description = normal mod. sınırlı kaynaklar ve otomatik gelen dalgalar. -mode.sandbox.name = Limitsiz Oynama -mode.sandbox.description = sonsuz kaynaklar ve dalgalar için zamanlayıcı yok. -mode.freebuild.name = Özgür Oynama -mode.freebuild.description = sınırlı kaynaklar ve dalgalar için zamanlayıcı yok. -upgrade.standard.name = standart -upgrade.standard.description = Standart mech. -upgrade.blaster.name = blaster -upgrade.blaster.description = Yavaş, zayıf bir mermi ateş eder. -upgrade.triblaster.name = triblaster -upgrade.triblaster.description = Bir yayında 3 mermi ateş eder. -upgrade.clustergun.name = clustergun -upgrade.clustergun.description = Yayılan bombalar ateş eder. -upgrade.beam.name = lazer -upgrade.beam.description = Uzun menzilli bir delici lazer ışını atar. -upgrade.vulcan.name = Vulkan -upgrade.vulcan.description = Hızlı mermiler ateş eder. -upgrade.shockgun.name = shockgun -upgrade.shockgun.description = Yıkıcı ve patlayıcı mermiler savurarak ateş eder. -item.stone.name = taş -item.iron.name = Demir -item.coal.name = kömür -item.steel.name = çelik -item.titanium.name = titanyum -item.dirium.name = dirium -item.uranium.name = uranyum -item.sand.name = kum -liquid.water.name = su -liquid.plasma.name = plazma -liquid.lava.name = lav -liquid.oil.name = petrol -block.weaponfactory.name = silah fabrikası -block.weaponfactory.fulldescription = Oyuncu mech için silah oluşturmak için kullanılır. Kullanmak için tıklayın. Kaynaklarını otomatik olarak çekirdekten alır. -block.air.name = hava -block.blockpart.name = blokparçası -block.deepwater.name = derin su -block.water.name = su -block.lava.name = lav -block.oil.name = petrol -block.stone.name = taş -block.blackstone.name = siyah taş -block.iron.name = Demir -block.coal.name = kömür -block.titanium.name = titanyum -block.uranium.name = uranyum -block.dirt.name = toprak -block.sand.name = kum -block.ice.name = buz -block.snow.name = kar -block.grass.name = Otlar -block.sandblock.name = kumbloku -block.snowblock.name = karbloku -block.stoneblock.name = taşbloku -block.blackstoneblock.name = blackstoneblock -block.grassblock.name = grassblock -block.mossblock.name = mossblock -block.shrub.name = çalı -block.rock.name = Kaya -block.icerock.name = ICEROCK -block.blackrock.name = Siyah Kaya -block.dirtblock.name = dirtblock -block.stonewall.name = taş duvar -block.stonewall.fulldescription = Ucuz bir savunma bloğu. İlk birkaç dalgada çekirdeği ve tareti korumak için kullanışlıdır. -block.ironwall.name = Demir duvar -block.ironwall.fulldescription = Temel bir savunma bloğu. Düşmanlardan korunma sağlar. Taş duvardan daha korunaklıdır. -block.steelwall.name = Çelik duvar -block.steelwall.fulldescription = Standart bir savunma bloğu. düşmanlardan korunma sağlar -block.titaniumwall.name = titanyum duvar -block.titaniumwall.fulldescription = Güçlü bir savunma bloğu. Düşmanlardan korunma sağlar. -block.duriumwall.name = dirium duvar -block.duriumwall.fulldescription = Çok güçlü bir savunma bloğu. Düşmanlardan korunma sağlar. -block.compositewall.name = kompozit duvar -block.steelwall-large.name = büyük çelik duvar -block.steelwall-large.fulldescription = Standart bir savunma bloğu. Birden fazla fayansa yayılır. -block.titaniumwall-large.name = büyük titanyum duvar -block.titaniumwall-large.fulldescription = Güçlü bir savunma bloğu. Birden fazla fayans yayılır. -block.duriumwall-large.name = büyük dirsek duvarı -block.duriumwall-large.fulldescription = Çok güçlü bir savunma bloğu. Birden fazla fayans yayılır. -block.titaniumshieldwall.name = korumalı duvar -block.titaniumshieldwall.fulldescription = Ekstra yerleşik bir kalkan ile güçlü bir savunma bloğu. Düşman mermilerini emmek için enerji kullanır. Bu bloğa enerji sağlamak için güç arttırıcıların kullanılması tavsiye edilir. -block.repairturret.name = onarım tareti -block.repairturret.fulldescription = Yakındaki hasarlı blokları yavaş bir hızda tamir eder. Küçük menzili vardır. Az miktarlarda güç kullanır. -block.megarepairturret.name = onarım tareti II -block.megarepairturret.fulldescription = Yakındaki hasarlı blokları tamir eder. Uygun menzillidir. Gücü kullanır. -block.shieldgenerator.name = kalkan üreteci -block.shieldgenerator.fulldescription = Gelişmiş bir savunma bloğu. Bir yarıçaptaki tüm blokları saldırıya karşı korur. Boştayken gücü yavaş bir hızda kullanır, ancak mermi temasında enerjiyi hızla boşaltır. -block.door.name = kapı -block.door.fulldescription = Dokunarak açılıp kapatılabilen bir blok. -block.door-large.name = büyük kapı -block.door-large.fulldescription = Dokunarak açılıp kapatılabilen bir blok. -block.conduit.name = sıvı borusu -block.conduit.fulldescription = Temel sıvı taşıma bloğu. Bir konveyör gibi çalışır, ancak sıvılar ile. pompa veya diğer borular ile kullanılır. Düşmanlar ve oyuncular için sıvılar üzerinde bir köprü olarak kullanılabilir. -block.pulseconduit.name = hızlı sıvı borusu -block.pulseconduit.fulldescription = Gelişmiş sıvı taşıma bloku. Sıvıları daha hızlı taşır ve standart sıvı taşıma borularından daha fazla sıvı depolar. -block.liquidrouter.name = sıvı yönlendirici -block.liquidrouter.fulldescription = Bir yönlendiriciye benzer şekilde çalışır. Bir taraftan sıvı girişi kabul eder ve diğer tarafa gönderir. Tek bir borudan diğer birçok boruyla sıvı paylaşmak için kullanışlıdır. -block.conveyor.name = konveyör -block.conveyor.fulldescription = En temel madde taşıma bloğu. Öğeleri konulduğu yöne göre maddeleri ileriye taşır ve bunları otomatik olarak taretlere ya da üretici bloklara getirir. konulmadan önce Döndürülebilirler, ancak konulduktan sonra Döndürülemezler. Düşmanlar ve oyuncular için sıvılar üzerinde bir köprü olarak kullanılabilir. -block.steelconveyor.name = çelik konveyör -block.steelconveyor.fulldescription = Gelişmiş madde taşıma bloğu. Öğeleri standart konveyörlerden daha hızlı taşır. -block.poweredconveyor.name = hızlı konveyör -block.poweredconveyor.fulldescription = Nihai ürün taşıma bloğu. Öğeleri çelik konveyörlerden daha hızlı taşır. -block.router.name = yönlendirici -block.router.fulldescription = Öğeleri bir yönden kabul eder ve 3 farklı yöne gönderir. Malzemelerin belirli bir miktarını da depolayabilir. Malzemelerin bir matkaptan çoklu taretlere ayrılması için uygundur. -block.junction.name = Kavşak noktası -block.junction.fulldescription = İki çapraz şekilde geçmeye çalışan konveyör bandı için köprü görevi görür. Farklı yerlere farklı malzemeler taşıyan konveyör olduğu durumlarda kullanışlıdır. -block.conveyortunnel.name = konveyör tüneli -block.conveyortunnel.fulldescription = Maddeleri blokların altından geçirmek için kullanılır. Kullanmak için, altına tünel yapılacak bloğun bir tarafta giriş tüneli ve diğer tarafa çıkış tüneli yerleştirin. Her iki tünelin de giriş veya çıkış yapan bloklara doğru zıt yönlere baktığından emin olun. -block.liquidjunction.name = sıvı bağlantı -block.liquidjunction.fulldescription = İki çaprazdan geçen boru için köprü görevi görür. Farklı yerlere farklı sıvılar taşıyan kanalların olduğu durumlarda kullanışlıdır. -block.liquiditemjunction.name = sıvı madde kavşağı -block.liquiditemjunction.fulldescription = Kanalları ve konveyörleri yan yana geçirmek için bir köprü görevi görür. -block.powerbooster.name = güç yükseltici -block.powerbooster.fulldescription = Gücü kendi yarıçapı içindeki tüm bloklara dağıtır. -block.powerlaser.name = güç lazeri -block.powerlaser.fulldescription = Önündeki bloğa güç ileten bir lazer oluşturur. Herhangi bir güç üretmez. En iyi jeneratörler veya diğer lazerler ile kullanılır. -block.powerlaserrouter.name = lazer yönlendirici -block.powerlaserrouter.fulldescription = Bir kerede gücü üç yöne dağıtan lazer. Bir jeneratörden birçok bloka güç verilmesi gereken durumlarda kullanışlıdır. -block.powerlasercorner.name = lazer köşesi -block.powerlasercorner.fulldescription = Bir kerede gücü iki yöne dağıtan lazer. Bir jeneratörden birçok bloka güç verilmesi gereken durumlarda ve bir yönlendiricinin kesin olmadığı durumlarda kullanışlıdır. -block.teleporter.name = teletaşıyıcı -block.teleporter.fulldescription = Gelişmiş madde taşıma bloğu. tele-taşıyıcı, öğeleri aynı renkte olan bir teletaşıyıcıya yönlendirir. Aynı renkte teletaşıyıcı yoksa, hiçbir şey yapmaz. Aynı renkten birden çok tele-yazıcı varsa, rastgele biri seçilir. Gücü kullanır. Rengi değiştirmek için dokunun. Not: Sadece madde ileten teletaşıyıcılar gücü kullanır. -block.sorter.name = ayrıştırıcı -block.sorter.fulldescription = Malzemeleri türüne göre ayrıştırır. Kabul edilecek malzeme bloktaki renkle gösterilir. Doğru materyal ile eşleşen tüm öğeler ileriye doğru çıkar, diğer her şey sol ve sağ taraflardan çıkar. -block.core.name = çekirdek -block.pump.name = pompa -block.pump.fulldescription = Kaynak bloğundan su, lav veya yağ gibi sıvıları pompalar. Yakındaki kanallara sıvıyı aktarır. -block.fluxpump.name = fluxpump -block.fluxpump.fulldescription = Pompanın gelişmiş bir versiyonu. Sıvıyı daha hızlı pompalar ve daha fazla sıvı depolar. -block.smelter.name = dökümcü -block.smelter.fulldescription = Temel üretim bloğu. 1 demir ve 1 kömür yakıt olarak verildiğinde, demir çıkarır. Tıkanmayı önlemek için farklı konveyörlerden demir ve kömürün kullanılması tavsiye edilir. -block.crucible.name = pota -block.crucible.fulldescription = Gelişmiş bir üretim bloğu. 1 titanyum, 1 çelik ve 1 kömür yakıt olarak girildiğinde, dirium çıkarır. Tıkanmayı önlemek için farklı konveyörlerden kömür, çelik ve titanyum kullanılması tavsiye edilir. -block.coalpurifier.name = kömür çıkarıcı -block.coalpurifier.fulldescription = Temel bir ekstraktör bloğu. Çok miktarda su ve taş ile birlikte tedarik edildiğinde kömür çıkarır. -block.titaniumpurifier.name = titanyum çıkarıcı -block.titaniumpurifier.fulldescription = Standart bir ekstraktör bloğu. Çok miktarda su ve demir ile birlikte verildiğinde titanyum çıkarır. -block.oilrefinery.name = yağ rafinerisi -block.oilrefinery.fulldescription = Büyük miktarda yağı kömür parçalarına ayırır. Kömür damarları kıt olduğunda kömür bazlı taretlerin yakıtı için kullanışlıdır. -block.stoneformer.name = taş biçimlendiricisi -block.stoneformer.fulldescription = Lavı taş haline getirir. Muazzam miktarda taş üretmek için kullanışlıdır. -block.lavasmelter.name = lav dökümcüsü -block.lavasmelter.fulldescription = Demiri çeliğe dönüştürmek için lav kullanır. Dökümcüler için bir alternatif. Kömürün az olduğu durumlarda kullanışlıdır -block.stonedrill.name = taş matkap -block.stonedrill.fulldescription = Temel bir matkap. Taş karolara yerleştirildiğinde, süresiz olarak yavaş bir hızda taş çıkarırç -block.irondrill.name = demir matkap -block.irondrill.fulldescription = Temel bir matkap. Demir cevheri çinileri üzerine yerleştirildiğinde, süresiz olarak yavaş bir şekilde demir çıkarıTemel bir matkap. Demir cevheri çinileri üzerine yerleştirildiğinde, süresiz olarak yavaş bir şekilde demir çıkarır.\n. -block.coaldrill.name = kömür matkap -block.coaldrill.fulldescription = Temel bir matkap. Kömür madeninin üzerine yerleştirildiğinde, süresiz olarak yavaş bir şekilde kömür çıkarır. -block.uraniumdrill.name = uranyum matkap -block.uraniumdrill.fulldescription = Gelişmiş bir matkap. Uranyum cevheri üzerine yerleştirildiğinde, uranyumu süresiz olarak yavaş bir hızda çıkarır. -block.titaniumdrill.name = titanyum matkap -block.titaniumdrill.fulldescription = Gelişmiş bir matkap. Titanyum cevherinin üzerine yerleştirildiğinde, sonsuza yavaş bir tempoda titanyum çıkar. -block.omnidrill.name = omnidrill -block.omnidrill.fulldescription = En büyük matkap. Herhangi bir cevherin uzerine yerlestitldiginde hızlı bir hızda cevher çıkarır -block.coalgenerator.name = kömür jeneratörü -block.coalgenerator.fulldescription = Gerekli jeneratör. Kömürden güç üretir. 4 tarafına lazer olarak güç verir. -block.thermalgenerator.name = termik jeneratör -block.thermalgenerator.fulldescription = Lavdan güç üretir. 4 tarafına lazer olarak güç verir. -block.combustiongenerator.name = yanma jeneratörü -block.combustiongenerator.fulldescription = Yağdan güç üretir. 4 tarafına lazer olarak güç verir. -block.rtgenerator.name = RTG jeneratörü -block.rtgenerator.fulldescription = Uranyumun radyoaktif bozunmasından az miktarda güç üretir. 4 tarafına lazer olarak güç verir. -block.nuclearreactor.name = nükleer reaktör -block.nuclearreactor.fulldescription = RTG Jeneratörünün gelişmiş bir versiyonu ve en iyi güç jeneratörüdür. Uranyumdan güç üretir. Su ile soğutulması gerekir. Son derece tehlikelidir; yetersiz miktarda su ile beslenmediğinde şiddetli patlayabilir. -block.turret.name = taret -block.turret.fulldescription = Basit, ucuz bir kule. Cephane için taş kullanır. Çift taretten biraz daha büyük menzillidir. -block.doubleturret.name = çift ​​taret -block.doubleturret.fulldescription = Taretin biraz daha güçlü bir versiyonu. Cephane için taş kullanır. standart tarete nazaran daha fazla hasar verir, ancak daha düşük bir menzile sahiptir. İki mermi ile ateş eder. -block.machineturret.name = gattling tareti -block.machineturret.fulldescription = Demir atan bir taret. Cephane için demir kullanır. İyi bir hasar ile ateş oranına sahiptir. -block.shotgunturret.name = splitter tareti -block.shotgunturret.fulldescription = Standart bir kule. Cephane için demir kullanır. tek atışta 7 mermi yayılır. Düşük menzillidir, ancak Gatling taretinden daha yüksek hasar verir. -block.flameturret.name = alev tareti -block.flameturret.fulldescription = Gelişmiş yakın menzilli taret. Cephane için kömür kullanır. Çok düşük bir menzile sahiptir, ancak çok yüksek hasar verir. Duvarların arkasında kullanılması tavsiye edilir. -block.sniperturret.name = çelik tareti -block.sniperturret.fulldescription = Gelişmiş uzun menzilli taret. Cephane için çelik kullanır. Yüksek hasar verir, ancak düşük ateş hızı vardır. Kullanımı pahalı, ancak yüksek menzili nedeniyle düşmanı uzak mesafelerden vurabilir. -block.mortarturret.name = flak tareti -block.mortarturret.fulldescription = Gelişmiş sıçrama hasarlı tareti. Cephane için kömür kullanır. Patlayan mermi şarapnel saysinde birden fazla düşman vurabilir. büyük düşman topluluklarını yok etmek için kullanışlıdır. -block.laserturret.name = lazer tareti -block.laserturret.fulldescription = Gelişmiş tek hedefli taret. Gücü kullanır. orta menzilli taret. Sadece tek hedefli. Asla ıskalamaz. -block.waveturret.name = tesla tareti -block.waveturret.fulldescription = Gelişmiş birçok hedefli taret. Gücü kullanır. Orta menzilli. Asla ıskalamaz. Düşük ile orta seviyede hasar verir, ancak aynı anda birden fazla düşmana vurabilir. -block.plasmaturret.name = plazma tareti -block.plasmaturret.fulldescription = Alev taretinin gelişmiş versiyonu. kömürü cephane olarak kullanır. Çok yüksek hasar, düşük ila orta menzil. -block.chainturret.name = zincir tareti -block.chainturret.fulldescription = En iyi hızlı ateş tareti. Uranyumu cephane olarak kullanır. Yüksek ateş hızı vardır. Orta menzillidir. Birden fazla blok boyunca yayılır. Son derece dayanıklıdır. -block.titancannon.name = titan topu -block.titancannon.fulldescription = En iyi uzak menzilli taret. Uranyumu cephane olarak kullanır. Orta ateş hızındadır ve top ateşinin sıçrama hasarı büyüktür. Uzun mesafe. Birden fazla blok boyunca yayılır. Son derece dayanıklıdır. -block.playerspawn.name = oyuncudoğuşu -block.enemyspawn.name = dϋşmandoğuşu +text.about=[ROYAL] Anuken tarafından oluşturuldu [] - [SKY] anukendev@gmail.com [] Aslen [turuncu] GDL [] Metal Monstrosity Jam. Kredi: - [SARI] ile yapılan SFX bfxr [] - [YEŞİL] RoccoW tarafından yapılan müzik [] / [kireç] bulunan FreeMusicArchive.org [] Özel teşekkürler: - [mercan] MitchellFJN []: Kapsamlı oyun testi ve geri bildirim - [sky] Luxray5474 []: wiki çalışması, kod katkıları - [kireç] Epowerj []: kod sistemi yapılandırması, icon - itch.io ve Google Play'deki tüm beta test kullanıcıları\n +text.credits=Yapımcılar +text.discord=Mindustry Discord'una katılın! +text.link.discord.description=Resmi Mindustry Discord iletişim kanalı +text.link.github.description=Oyunun kaynak kodu +text.link.dev-builds.description=Geliştirme altında olan sürüm +text.link.trello.description=Planlanan özellikler için resmi Trello Bülteni +text.link.itch.io.description=PC yüklemeleri ve web sürümü ile itch.io sayfası +text.link.google-play.description=Google Play mağaza sayfası +text.link.wiki.description=Resmi Mindustry Wikipedi'si +text.linkfail=Bağlantı açılamadı! URL, yazı tahtanıza kopyalandı. +text.editor.web=Web sürümü editörü desteklemiyor! Editörü kullanmak için oyunu indirin. +text.multiplayer.web=Oyunun bu sürümü çok oyunculuyu desteklemiyor! Tarayıcınızdan çok oyunculu oynamak için, itch.io sayfasındaki "çok oyunculu web sürümü" bağlantısını kullanın. +text.gameover=Çekirdek yok edildi. +text.highscore=[SARI] Yeni yüksek puan! +text.lasted=Dalgaya kadar sürdün +text.level.highscore=Yüksek Puan: [accent] {0} +text.level.delete.title=Silmeyi onaylayın +text.level.select=Seviye Seç +text.level.mode=Oyun Modu +text.savegame=Oyunu Kaydet +text.loadgame=Oyunu yükle +text.joingame=Oyuna katıl +text.newgame=Yeni Oyun +text.quit=Çık +text.about.button=Hakkında +text.name=Adı: +text.players=1090 oyuncu çevrimiçi +text.players.single={0} Oyuncu Çevrimiçi +text.server.mismatch=Paket hatası: olası istemci / sunucu sürümü uyuşmazlığı. Siz ve ev sahibi Mindustry'nin en son sürümüne sahip olduğunuzdan emin olun! +text.server.closing=[accent] Sunucu kapatılıyor ... +text.server.kicked.kick=Sunucudan kovuldun! +text.server.kicked.invalidPassword=Geçersiz şifre! +text.server.kicked.clientOutdated=Oyun sürümünüz geçerli değil. Oyununu güncelleyin! +text.server.kicked.serverOutdated=Eski sunucu! Ev sahibinden güncellemesini isteyin! +text.server.kicked.banned=Bu sunucudan yasaklandınız. +text.server.kicked.recentKick=Son zamanlarda tekmelendin. Tekrar bağlanmadan önce bekleyin. +text.server.connected={0} katıldı. +text.server.disconnected={0} bağlantısı kesildi. +text.nohost=Özel bir haritada sunucuyu barındıramıyor! +text.host.info=[Vurgu] ana bilgisayarı [] düğmesi, [657] [65] [65] ve [65] [6568] bağlantı noktalarında bir sunucuyu barındırır. [] Aynı [LIGHT_GRAY] wifi veya yerel ağ [] üzerindeki herkes sunucunuzu sunucularında görebilir. liste. Kişilerin IP tarafından herhangi bir yerden bağlanabilmesini istiyorsanız [vurgu] bağlantı noktası iletme [] gereklidir. [LIGHT_GRAY] Not: Birisi LAN oyununuza bağlanırken sorun yaşıyorsa, güvenlik duvarı ayarlarınızda Mindustry'e yerel ağınıza erişebildiğinizden emin olun. +text.join.info=Burada, bağlanmak için yerel ağ [] sunucularına bağlanmak ya da [aksan] sunucularını bulmak için bir [vurgu] sunucunun IP [] girebilirsiniz. Hem LAN hem de WAN çok oyunculu desteklenir. [LIGHT_GRAY] Not: Otomatik bir global sunucu listesi yoktur; Birisine IP ile bağlanmak isterseniz, ana bilgisayardan kendi IP adreslerini sormanız gerekir. +text.hostserver=Oyunu Sun +text.host=evsahibi +text.hosting=[accent] Sunucu açılıyor ... +text.hosts.refresh=Yenile +text.hosts.discovering=LAN oyunlarını keşfetme +text.server.refreshing=Canlandırıcı sunucu +text.hosts.none=[lightgray] Hayır LAN oyunları bulundu! +text.host.invalid=[scarlet] Ana bilgisayara bağlanılamıyor. +text.server.friendlyfire=Dost ateşi +text.trace=Oyuncuyu Takip Et +text.trace.playername=Oyuncu adı: [accent] {0} +text.trace.ip=IP: [vurgu] {0} +text.trace.id=Benzersiz kimlik: [accent] {0} +text.trace.android=Android : [accent] {0} +text.trace.modclient=Özel Alıcı: [accent] {0} +text.trace.totalblocksbroken=Toplam kırık blok: [accent] {0} +text.trace.structureblocksbroken=Kırılan yapı blokları: [accent] {0} +text.trace.lastblockbroken=Kırılan son blok: [accent] {0} +text.trace.totalblocksplaced=Toplam blok yerleştirildi: [accent] {0} +text.trace.lastblockplaced=Konulan son blok: [accent] {0} +text.invalidid=Geçersiz alıcı kimliği! Bir hata raporu gönderin. +text.server.bans=yasaklar +text.server.bans.none=Yasaklanmış oyuncu bulunamadı! +text.server.admins=Yöneticiler +text.server.admins.none=Yönetici bulunamadı! +text.server.add=Sunucu ekle +text.server.delete=Bu sunucuyu silmek istediğinizden emin misiniz? +text.server.hostname=Sun +text.server.edit=Sunucuyu Düzenle +text.server.outdated=[crimson] Eski Sunucu! +text.server.outdated.client=[crimson] Eski Alıcı! +text.server.version=[lightgray] Sürüm: {0} +text.server.custombuild=[sarı] Özel Yapım +text.confirmban=Bu oyuncuyu yasaklamak istediğinizden emin misiniz? +text.confirmunban=Bu oyuncunun yasağını kaldırmak istediğinden emin misin? +text.confirmadmin=Bu oyuncunun yönetici yapmak istediğinden emin misin? +text.confirmunadmin=Bu oyuncudan yönetici durumunu kaldırmak istediğinizden emin misiniz? +text.joingame.title=Oyuna katılmak +text.joingame.ip=IP: +text.disconnect=Bağlantı Kesildi +text.disconnect.data=Dünya verileri yüklenemedi! +text.connecting=[Vurgu] bağlanıyor ... +text.connecting.data=[accent] Dünya verileri yükleniyor ... +text.connectfail=[crimson] Sunucuya bağlanılamadı: [orange] {0} +text.server.port=Liman +text.server.addressinuse=Adres çoktan kullanımda! +text.server.invalidport=Bağlantı noktası numarası geçersiz. +text.server.error=[crimson] Sunucu barındırma hatası: [orange] {0} +text.save.new=6349,Yeni Kayıt +text.save.overwrite=Bu kayıt yuvasının üzerine yazmak istediğinizden emin misiniz? +text.overwrite=Üzerine Yaz +text.save.none=Hiçbir kayıt bulunamadı! +text.saveload=[Vurgu] Kaydediliyor ... +text.savefail=Oyun kaydedilemedi! +text.save.delete.confirm=Bu kaydı silmek istediğinizden emin misiniz? +text.save.delete=Sil +text.save.export=Dışa Aktar +text.save.import.invalid=[turuncu] Bu kayıt geçersiz! +text.save.import.fail=[crimson] Kayıt oyuna aktarılamadı : [orange] {0} +text.save.export.fail=[crimson] Kayıt dışa aktarılamadı: [orange] {0} +text.save.import=İçe Aktar +text.save.newslot=İsmi kaydet: +text.save.rename=Yeniden Adlandır +text.save.rename.text=Yeni İsim: +text.selectslot=Bir kayıt seçin. +text.slot=[accent] Yuva {0} +text.save.corrupted=[orange] Kayıt dosyası bozuk veya geçersiz! +text.empty= +text.on=Açık +text.off=Kapalı +text.save.autosave=Otomatik kaydetme: {0} +text.save.map=harita +text.save.wave=Dalga +text.save.difficulty=zorluk +text.save.date=Son Kaydedilen: {0} +text.confirm=Onayla +text.delete=Sil +text.ok=Tamam +text.open=Açık +text.cancel=İptal +text.openlink=Linki aç +text.copylink=Bağlantıyı kopyala +text.back=Geri +text.quit.confirm=Çıkmak istediğinden emin misin? +text.changelog.title=Değişiklik listesi +text.changelog.loading=Değişiklik listesi yükleniyor +text.changelog.error.android=[turuncu] Android'da olan hata nedeniyle değişiklik listesi görüntülenemiyor. +text.changelog.error=[scarlet] Değişiklik listesi alma hatası! İnternet bağlantınızı kontrol edin. +text.changelog.current=[sarı] [[Güncel versiyon] +text.changelog.latest=[turuncu] [[Son sürüm] +text.loading=[Vurgu] Yükleniyor ... +text.wave=[turuncu] Dalga {0} +text.wave.waiting={0} içinde dalga +text.waiting=Bekleniyor +text.enemies={0} Düşmanlar +text.enemies.single={0} Düşman +text.loadimage=Resmi yükle +text.saveimage=Resmi Kaydet +text.editor.badsize=[orange] Resim boyutları geçersiz! [] Geçerli harita boyutları: {0} +text.editor.errorimageload=Resim dosyası yüklenirken hata oluştu: [orange] {0} +text.editor.errorimagesave=Resim dosyası kaydedilirken hata oluştu: [orange] {0} +text.editor.generate=Üretmek +text.editor.resize=Yeniden Boyutlandırma +text.editor.loadmap=Harita Yükle +text.editor.savemap=Harita Kaydet +text.editor.loadimage=Resmi yükle +text.editor.saveimage=Resmi Kaydet +text.editor.unsaved=[scarlet] Kaydedilmemiş değişiklikleriniz var! [] Çıkmak istediğinizden emin misiniz? +text.editor.resizemap=Haritayı Yeniden Boyutlandır +text.editor.mapname=Harita Adı +text.editor.overwrite=[Vurgu] Uyarı! Bu mevcut bir haritanın üzerine yazar. +text.editor.selectmap=Yüklenecek bir harita seçin: +text.width=Genişliği: +text.height=Boy: +text.menu=Menü +text.play=Oyna +text.load=Yükle +text.save=Kaydet +text.language.restart=Lütfen dil ayarlarının etkili olması için oyununuzu yeniden başlatın. +text.settings.language=Dil +text.settings=Ayarlar +text.tutorial=Eğitim +text.editor=Editör +text.mapeditor=Harita Editörü +text.donate=Bağışlamak +text.settings.reset=Varsayılanlara Dön +text.settings.controls=kontroller +text.settings.game=Oyun +text.settings.sound=Ses +text.settings.graphics=Grafik +text.upgrades=Geliştirmeler +text.purchased=[KİREÇ] Yap၊ld၊ +text.weapons=Silahlar +text.paused=Duraklatıldı +text.info.title=[Vurgu] Bilgi +text.error.title=[crimson] Bir hata oluştu +text.error.crashtitle=Bir hata oluştu +text.blocks.blockinfo=Blok Bilgisi +text.blocks.powercapacity=Güç kapasitesi +text.blocks.powershot=Güç / atış +text.blocks.size=Boyut +text.blocks.liquidcapacity=Sıvı kapasitesi +text.blocks.maxitemssecond=Maksimum öğe / saniye +text.blocks.powerrange=Güç aralığı +text.blocks.itemcapacity=Ürün kapasitesi +text.blocks.inputliquid=Giriş sıvı +text.blocks.inputitem=Giriş öğesi +text.blocks.explosive=Çok patlayıcı! +text.blocks.health=Can +text.blocks.inaccuracy=yanlışlık +text.blocks.shots=atışlar +text.blocks.inputcapacity=Giriş kapasitesi +text.blocks.outputcapacity=Çıkış kapasitesi +setting.difficulty.easy=kolay +setting.difficulty.normal=orta +setting.difficulty.hard=zor +setting.difficulty.insane=deli +setting.difficulty.purge=tasfiye +setting.difficulty.name=Zorluk: +setting.screenshake.name=Ekran Sallamak +setting.indicators.name=Düşman Göstergeleri +setting.effects.name=Görüntü Efektleri +setting.sensitivity.name=Denetleyici hassasiyeti +setting.saveinterval.name=Otomatik Kaydetme Aralığı +setting.seconds=saniye +setting.fullscreen.name=Tam ekran +setting.multithread.name=Çok iş parçacığı +setting.fps.name=Saniyede ... Kare göstermek +setting.vsync.name=VSync +setting.lasers.name=Güç Lazerleri Göster +setting.healthbars.name=Varlık Sağlık çubuklarını göster +setting.musicvol.name=Müzik sesi +setting.mutemusic.name=Müziği Kapat +setting.sfxvol.name=SFX Hacmi +setting.mutesound.name=Sesi kapat +map.maze.name=Labirent +map.fortress.name=Kale +map.sinkhole.name=düden +map.caves.name=mağaralar +map.volcano.name=volkan +map.caldera.name=kaldera +map.scorch.name=alazlamak +map.desert.name=çöl +map.island.name=ada +map.grassland.name=Çayır +map.tundra.name=tundra +map.spiral.name=sarmal +map.tutorial.name=Eğitim +text.keybind.title=Tuşları yeniden ayarla +keybind.move_x.name=sağ / sol +keybind.move_y.name=yukarı / aşağı +keybind.select.name=seçmek +keybind.break.name=kırmak +keybind.shoot.name=ateş etme +keybind.zoom_hold.name=tut ve büyüt +keybind.zoom.name=Yakınlaştır +keybind.block_info.name=blok bilgisi +keybind.menu.name=menü +keybind.pause.name=duraklatma +keybind.dash.name=tire +keybind.chat.name=Sohbet +keybind.player_list.name=oyuncu listesi +keybind.console.name=KONTROL MASASI +keybind.rotate_alt.name=rotate_alt +keybind.rotate.name=Döndür +mode.text.help.title=Modların açıklaması +mode.waves.name=dalgalar +mode.waves.description=normal mod. sınırlı kaynaklar ve otomatik gelen dalgalar. +mode.sandbox.name=Limitsiz Oynama +mode.sandbox.description=sonsuz kaynaklar ve dalgalar için zamanlayıcı yok. +mode.freebuild.name=Özgür Oynama +mode.freebuild.description=sınırlı kaynaklar ve dalgalar için zamanlayıcı yok. +item.stone.name=taş +item.coal.name=kömür +item.titanium.name=titanyum +item.sand.name=kum +liquid.water.name=su +liquid.lava.name=lav +liquid.oil.name=petrol +block.door.name=kapı +block.door-large.name=büyük kapı +block.conduit.name=sıvı borusu +block.pulseconduit.name=hızlı sıvı borusu +block.liquidrouter.name=sıvı yönlendirici +block.conveyor.name=konveyör +block.router.name=yönlendirici +block.junction.name=Kavşak noktası +block.liquidjunction.name=sıvı bağlantı +block.sorter.name=ayrıştırıcı +block.smelter.name=dökümcü +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.name=Thorium +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index 58caee33e5..7a85ec0af1 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -1,500 +1,495 @@ -text.about = Створено [ROYAL] Anuken. []\nСпочатку запис у [orange] GDL [] MM Jam.\nТворці:\n- SFX зроблено з [YELLOW] bfxr []\n- Музика зроблена [GREEN] RoccoW [] / Знайдено на [lime] FreeMusicArchive.org [] \nОсоблива подяка:\n- [coral] MitchellFJN []: екстенсивне тестування та відгуки\n- [sky] Luxray5474 []: робота з вікі, вклади коду\n- Всі бета-тестери на itch.io та Google Play\n -text.discord = Приєднуйтесь до нашого Discord! -text.changes = [SCARLET] Увага! \n[] Деякі важливі механіки гри були змінені.\n- [accent] Телепорти [] тепер використовують електроенергію. \n- [accent] Домінна піч [] та [accent] Тиглі [] тепер мають ліміт. \n- [accent] Тиглі [] зараз вимагають вугілля як паливо. -text.gameover = Ядро було зруйновано. -text.highscore = [YELLOW] Новий рекорд! -text.lasted = Ви тримались до хвилі -text.level.highscore = Рекорд: [accent] {0} -text.level.delete.title = Підтвердьте видалення -text.level.delete = Ви впевнені, що хочете видалити карту \"[orange] {0} \"? -text.level.select = Вибір рівня -text.level.mode = Ігровий режим -text.savegame = Зберегти гру -text.loadgame = Завантажити гру -text.joingame = Приєднатися\nдо гри +text.about=Створено [ROYAL] Anuken. []\nСпочатку запис у [orange] GDL [] MM Jam.\nТворці:\n- SFX зроблено з [YELLOW] bfxr []\n- Музика зроблена [GREEN] RoccoW [] / Знайдено на [lime] FreeMusicArchive.org [] \nОсоблива подяка:\n- [coral] MitchellFJN []: екстенсивне тестування та відгуки\n- [sky] Luxray5474 []: робота з вікі, вклади коду\n- Всі бета-тестери на itch.io та Google Play\n +text.discord=Приєднуйтесь до нашого Discord! +text.gameover=Ядро було зруйновано. +text.highscore=[YELLOW] Новий рекорд! +text.lasted=Ви тримались до хвилі +text.level.highscore=Рекорд: [accent] {0} +text.level.delete.title=Підтвердьте видалення +text.level.select=Вибір рівня +text.level.mode=Ігровий режим +text.savegame=Зберегти гру +text.loadgame=Завантажити гру +text.joingame=Приєднатися\nдо гри text.newgame=Нова гра -text.quit = Вийти -text.about.button = Про -text.name = Назва: -text.public = Публічний -text.players = {0} гравців онлайн -text.server.player.host = {0} (host) -text.players.single = {0} гравців онлайн -text.server.mismatch = Пакетна помилка: невідповідність версії версії клієнта / сервера. Переконайтеся, що ви та хост мають останню версію Mindustry! -text.server.closing = [accent] Закриття сервера ... -text.server.kicked.kick = Ви були вигнані з сервера! -text.server.kicked.invalidPassword = Невірний пароль! -text.server.kicked.clientOutdated = Застарілий клієнт! Оновіть свою гру! -text.server.kicked.serverOutdated = Застарілий сервер! Попросіть хост оновити! -text.server.connected = {0} приєднався. -text.server.disconnected = {0} від'єднано. -text.nohost = Неможливо розмістити сервер на власній карті! -text.hostserver = Хост-сервер -text.host = Хост -text.hosting = [accent] Відкриття сервера ... -text.hosts.refresh = Оновити -text.hosts.discovering = Знайомство з мережевими іграми -text.server.refreshing = Оновити сервери -text.hosts.none = [lightgray] Ніяких ігор у мережі не знайдено! -text.host.invalid = [scarlet] Неможливо підключитися до хосту. -text.server.friendlyfire = Дружній вогонь -text.server.add = Додати сервер -text.server.delete = Ви впевнені, що хочете видалити цей сервер? -text.server.hostname = Хост: {0} -text.server.edit = Редагувати сервер -text.joingame.byip = [] Приєднатися по IP ...[] -text.joingame.title = Приєднатися до гри -text.joingame.ip = IP -text.disconnect = Роз'єднано -text.connecting = [accent] Підключення ... -text.connecting.data = [accent] Завантаження світових даних ... -text.connectfail = [crimson] Не вдалося підключитися до сервера: [orange] {0} -text.server.port = Порт -text.server.addressinuse = Адреса вже використовується! -text.server.invalidport = Недійсний номер порту. -text.server.error = [crimson] Помилка хостингу сервера: [orange] {0} -text.tutorial.back = < Попер. -text.tutorial.next = Далі > -text.save.new = Нове збереження -text.save.overwrite = Ви впевнені, що хочете перезаписати цей слот для збереження? -text.overwrite = Перезаписати -text.save.none = Не знайдено жодних збережень! -text.saveload = [accent] Збереження ... -text.savefail = Не вдалося зберегти гру! -text.save.delete.confirm = Ви впевнені, що хочете видалити це збереження? -text.save.delete = Видалити -text.save.export = Експорт збереження -text.save.import.invalid = [orange] Це збереження недійсне! -text.save.import.fail = [crimson] Не вдалося імпортувати збереження: [orange] {0} -text.save.export.fail = [crimson] Не вдалося експортувати збереження: [orange] {0} -text.save.import = Імпортувати збереження -text.save.newslot = Назва збереження: -text.save.rename = Переіменувати -text.save.rename.text = Нова назва: -text.selectslot = Виберіть збереження. -text.slot = [accent] слот {0} -text.save.corrupted = [orange] Збережений файл пошкоджений або він невірний! -text.empty = <порожньо> -text.on = Увімкнути -text.off = Вимкнути -text.save.autosave = Автозбереження: {0} -text.save.map = Карта -text.save.wave = Хвиля {0} -text.save.difficulty = Складність -text.save.date = Останнє збережено: {0} -text.confirm = Підтвердити -text.delete = Видалити -text.ok = ОК -text.open = Відкрити -text.cancel = Скасувати -text.openlink = Відкрити посилання -text.back = Назад -text.quit.confirm = Ти впевнений що хочеш піти? -text.loading = [accent] Завантаження ... -text.wave = [orange] хвиля {0} -text.wave.waiting = Хвиля через {0} -text.waiting = Очікування… -text.enemies = {0} Вороги -text.enemies.single = Противник -text.loadimage = Завантажити зображення -text.saveimage = Зберегти зображення -text.oregen = Генерація руд -text.editor.badsize = [orange] Недійсні розміри зображення! [] Дійсні розміри карти: {0} -text.editor.errorimageload = Помилка завантаження файлу зображень: [orange] {0} -text.editor.errorimagesave = Помилка збереження файлу зображення: [orange] {0} -text.editor.generate = Генератор -text.editor.resize = Змінити розмір -text.editor.loadmap = // Завантажити карту -text.editor.savemap = Зберегти карту -text.editor.loadimage = Завантажити зображення -text.editor.saveimage = Зберегти зображення -text.editor.unsaved = [scarlet] У вас є незбережені зміни! [] Ви впевнені, що хочете вийти? -text.editor.brushsize = Розмір пензля: {0} -text.editor.noplayerspawn = Ця карта не має ігрового поля для гравця! -text.editor.manyplayerspawns = Карти не можуть мати більше одного ігрового поля для гравців! -text.editor.manyenemyspawns = Не може бути більше ніж {0} ворожих точок! -text.editor.resizemap = Змінити розмір карти -text.editor.resizebig = [scarlet] Попередження! [] Карти, розмір яких перевищує 256 одиниць, можуть виснути і можуть бути нестабільними. -text.editor.mapname = Назва карти: -text.editor.overwrite = [accent] Попередження! Це перезаписує існуючу карту. -text.editor.failoverwrite = [crimson] Неможливо перезаписати карту за замовчуванням! -text.editor.selectmap = Виберіть карту для завантаження: -text.width = Ширина -text.height = Висота -text.randomize = Рандомізувати -text.apply = Застосувати -text.update = Оновити -text.menu = Меню -text.play = Відтворити -text.load = Завантаження -text.save = Зберегти -text.language.restart = Будь ласка, перезапустіть свою гру, щоб налаштування мови набули чинності. -text.settings.language = Мова -text.settings = Налаштування -text.tutorial = Навчальний\nпосібник -text.editor = Редактор -text.mapeditor = Редактор карт -text.donate = Підтримати проект -text.settings.reset = Скинути до стандартних -text.settings.controls = Елементи управління -text.settings.game = Гра -text.settings.sound = Звук -text.settings.graphics = Графіка -text.upgrades = Оновлення -text.purchased = [LIME] Створено! -text.weapons = Зброя -text.paused = Пауза -text.respawn = Відновлення за -text.info.title = [accent] інформація -text.error.title = [crimson] Виникла помилка -text.error.crashmessage = [SCARLET] Виникла несподівана помилка, що призвела до збою. [] Будь ласка, повідомте про конкретні обставини, розробнику: [ORANGE] anukendev@gmail.com [] -text.error.crashtitle = Виникла помилка -text.mode.break = Режим зносу: {0} -text.mode.place = Режим будівництва: {0} -placemode.hold.name = Лінія -placemode.areadelete.name = Площа -placemode.touchdelete.name = Дотик -placemode.holddelete.name = Утримування. -placemode.none.name = (None) -placemode.touch.name = Дотик -placemode.cursor.name = курсор -text.blocks.extrainfo = [accent] додатковий інформаційний блок: -text.blocks.blockinfo = Блокування інформації -text.blocks.powercapacity = Потужність -text.blocks.powershot = Потужність / постріл -text.blocks.powersecond = Потужність / секунда -text.blocks.powerdraindamage = Потужність дренажу / пошкодження -text.blocks.shieldradius = Радіус щита -text.blocks.itemspeedsecond = Швидкість / секунда -text.blocks.range = Радіус -text.blocks.size = Розмір -text.blocks.powerliquid = Потужність / Рідина -text.blocks.maxliquidsecond = Макс. Рідина / секунда -text.blocks.liquidcapacity = Ємкість рідини -text.blocks.liquidsecond = Рідина / секунда -text.blocks.damageshot = Пошкодження / постріл -text.blocks.ammocapacity = Місткість боєприпасів -text.blocks.ammo = Набої -text.blocks.ammoitem = Боєприпаси / предмет -text.blocks.maxitemssecond = Макс. Елементи / секунду -text.blocks.powerrange = Радіус потужності -text.blocks.lasertilerange = Радіус лазерних плиток -text.blocks.capacity = Ємкість -text.blocks.itemcapacity = Ємкість предмету -text.blocks.maxpowergenerationsecond = Максимальна потужність / секунда -text.blocks.powergenerationsecond = Потужність / секунда -text.blocks.generationsecondsitem = Генерація за секунду / предмет -text.blocks.input = Ввід -text.blocks.inputliquid = Ввід речовини -text.blocks.inputitem = Вхідний матеріал -text.blocks.output = Вивід -text.blocks.secondsitem = Секунда / предмет -text.blocks.maxpowertransfersecond = Максимальна передача потужності / секунда -text.blocks.explosive = Вибухонебезпечний! -text.blocks.repairssecond = Ремонт / секунда -text.blocks.health = Здоров'я -text.blocks.inaccuracy = Неточність -text.blocks.shots = Постріли -text.blocks.shotssecond = Постріли / секунду -text.blocks.fuel = Паливо: -text.blocks.fuelduration = Тривалість палива -text.blocks.maxoutputsecond = Макс. Вихід / секунду -text.blocks.inputcapacity = Вхідна ємність -text.blocks.outputcapacity = Випускна ємність -text.blocks.poweritem = Потужність / виріб -text.placemode = Місцевий режим -text.breakmode = Перерваний режим -text.health = Здоров'я -setting.difficulty.easy = Легкий -setting.difficulty.normal = Нормальний -setting.difficulty.hard = Важкий -setting.difficulty.insane = Божевільний -setting.difficulty.purge = Очистити -setting.difficulty.name = Складність -setting.screenshake.name = Тряска екрана -setting.smoothcam.name = Гладка камера -setting.indicators.name = Індикатори ворога -setting.effects.name = Ефекти відображення -setting.sensitivity.name = Чутливість контролера -setting.saveinterval.name = Інтервал автозбереження -setting.seconds = {0} секунд -setting.fullscreen.name = Повноекранний -setting.multithread.name = Багатопотоковий [scarlet] (нестабільний!) -setting.fps.name = Показати FPS -setting.vsync.name = VSunc -setting.lasers.name = Показати енергетичні лазери -setting.healthbars.name = Показати здоров'я -setting.pixelate.name = Пікселяція екрану -setting.musicvol.name = Гучність музики -setting.mutemusic.name = Вимкнути музику -setting.sfxvol.name = Гучність ефектів -setting.mutesound.name = Вимкнути звук -map.maze.name = Лабіринт -map.fortress.name = Фортеця -map.sinkhole.name = Свердловина -map.caves.name = Печери -map.volcano.name = Вулкан -map.caldera.name = Кальдера -map.scorch.name = Мертва земля -map.desert.name = Пустеля -map.island.name = Острів -map.grassland.name = Пасовища -map.tundra.name = Тундра -map.spiral.name = Спіраль -map.tutorial.name = Навчання -tutorial.intro.text = [yellow] Ласкаво просимо до підручника. [] Для початку натисніть \"далі\". -tutorial.moveDesktop.text = Для переміщення використовуйте клавіші [orange] ​​[[WASD] []. Утримуйте [orange] SHIFT[], для прискорення. Утримуйте [orange] CTRL [], використовуючи [orange] колесо прокручування [] для збільшення або зменшення. -tutorial.shoot.text = Використовуйте мишу, щоб націлитись, утримуйте [orange] ліву кнопку миші [], щоб стріляти. Попрактикуйтесь на [yellow] мішені []. -tutorial.moveAndroid.text = Щоб перетягнути панораму, перетягніть один палець по екрану. Використовуйте два пальця, щоб збільшити чи зменшити маштаб. -tutorial.placeSelect.text = Спробуйте вибрати [yellow] конвеєр [] у меню блоку внизу справа. -tutorial.placeConveyorDesktop.text = Використовуйте [orange] [[колесико миші] [], щоб повернути конвеєр [orange] вперед [], а потім помістіть його в [yellow] позначене місце [], використовуючи [orange] [[ліву кнопку миші] []. -tutorial.placeConveyorAndroid.text = Використовуйте [orange] [[кнопку оберту] [], щоб обернути конвеєр [оранжевий] вперед [], перетягуйте його одним пальцем, а потім помістіть його в [yellow] позначене місце [], використовуючи [orange] [[галочка][]. -tutorial.placeConveyorAndroidInfo.text = Крім того, ви можете натиснути піктограму перехрестя внизу ліворуч, щоб переключитися на [orange] [[сенсорний режим]] [], і помістити блоки, натиснувши на екран. У сенсорному режимі блоки можна повертати зі стрілкою внизу ліворуч. Натисніть [yellow] наступний [], щоб спробувати. -tutorial.placeDrill.text = Тепер виберіть та розмістіть [yellow] кам'яне свердло [] у зазначеному місці. -tutorial.blockInfo.text = Якщо ви хочете дізнатись більше про блок, ви можете торкнутися [orange] знак питання [] у верхньому правому куті, щоб прочитати його опис. -tutorial.deselectDesktop.text = Ви можете вимкнути блок, використовуючи [orange] [[клацання правою кнопкою миші] []. -tutorial.deselectAndroid.text = Ви можете скасувати вибір блоку, натиснувши кнопку [orange] X []. -tutorial.drillPlaced.text = Дриль тепер видобуває [yellow] камінь, [] та виведе його на конвеєр, а потім переміщає його в [yellow] ядро []. -tutorial.drillInfo.text = Різні руди потребують різних дрилі. Камінь вимагає кам'яні свердла, залізо вимагає залізні свердла та ін -tutorial.drillPlaced2.text = Переміщення елементів у ядро ​​вказує їх у ваш [yellow] предметний інвентар [] у верхньому лівому куті. Розміщення блоків використовує предмети з вашого інвентарю. -tutorial.moreDrills.text = Ви можете пов'язати багато свердлів і конвеєрів разом в одну гілку конвеєра. -tutorial.deleteBlock.text = Ви можете видалити блоки, натиснувши правою клавішею [orange] правою кнопкою миші [] по блоці, який ви хочете видалити. Спробуйте видалити цей конвеєр. -tutorial.deleteBlockAndroid.text = Ви можете видалити блоки за допомогою [orange], перехрестя [] в меню [mode] зламу [orange] у нижньому лівому куті та натиснувши на блок. Спробуйте видалити цей конвеєр. -tutorial.placeTurret.text = Тепер виділіть та розмістіть [yellow] турель [] у [yellow] позначеному місці []. -tutorial.placedTurretAmmo.text = Ця турель тепер приймає [yellow] боєприпас [] з конвеєра. Ви можете побачити, скільки боєприпасів вона має, натискаючи на неї і перевіряючи [green] зелену полоску []. -tutorial.turretExplanation.text = Турелі будуть автоматично стріляти у найближчого ворога, якщо вони мають достатню кількість боєприпасів. -tutorial.waves.text = Кожні [yellow] 60 [] секунд, хвиля [coral] ворогів [] буде виникати в певних місцях і намагатися знищити ядро. -tutorial.coreDestruction.text = Ваша мета полягає в тому, щоб [yellow] захищати ядро []. Якщо ядро ​​знищено, ви [coral] програєте[]. -tutorial.pausingDesktop.text = Якщо вам коли-небудь потрібно зробити перерву, натисніть кнопку [orange] паузи [] у верхньому лівому куті або на кнопку [orange] пропуск [], щоб призупинити гру. Ви можете вибрати і розмістити блоки під час призупинення, але не можете переміщатися чи стріляти. -tutorial.pausingAndroid.text = Якщо вам коли-небудь потрібно зробити перерву, натисніть кнопку [orange] пауза [] у верхньому лівому куті, щоб призупинити гру. Ти можеш ще знищувати та будувати блоки під час призупинення. -tutorial.purchaseWeapons.text = Ви можете придбати нову [yellow] зброю [] для вашого механізму, відкривши меню оновлення в лівому нижньому кутку. -tutorial.switchWeapons.text = Перемикати зброю будь-яким натисканням його піктограми внизу ліворуч або за допомогою цифр [orange] [[1-9] []. -tutorial.spawnWave.text = Ось хвиля зараз. Знищи їх -tutorial.pumpDesc.text = У пізніших хвилях, можливо, доведеться використовувати [yellow] насоси [] для розподілу рідин для генераторів або екстракторів. -tutorial.pumpPlace.text = Насоси працюють аналогічно свердлам, за винятком того, що вони виробляють рідини замість предметів. Спробуйте встановити насос на [yellow] призначене мастило []. -tutorial.conduitUse.text = Тепер покладіть [orange] трубопровід [], віддаляючись від насоса. -tutorial.conduitUse2.text = І ще кілька ... -tutorial.conduitUse3.text = І ще кілька ... -tutorial.generator.text = Тепер, помістіть блок [orange] ​​базовий генератор енергії [] в кінці каналу. -tutorial.generatorExplain.text = Цей генератор тепер створить [yellow] енергію [] від масла. -tutorial.lasers.text = Потужність розподіляється за допомогою [yellow] лазерів потужності []. Поверніть і помістіть його тут. -tutorial.laserExplain.text = Тепер генератор переведе енергію в лазерний блок. Промінь [yellow] непрозорий [] означає, що в даний час він передає потужність, а промінь [yellow] прозорий [] означає, що це не так. -tutorial.laserMore.text = Ви можете перевірити, скільки енергії в блоку, наведіть курсор миші на нього і перевірте [yellow] жовту стрічку [] у верхній частині екрана. -tutorial.healingTurret.text = Цей лазер може бути використаний для живлення турелі для ремонту [lime] []. Помістіть одну тут. -tutorial.healingTurretExplain.text = Поки вона має енергію, ця турель може [lime] відремонтувати блоки. [] Під час гри постарайтеся збудувати одну таку чим швидше! -tutorial.smeltery.text = Для багатьох блоків потрібна [orange] сталь [], для цього потрібна[orange] доминна піч [] . Місце тут. -tutorial.smelterySetup.text = Ця піч буде тепер виробляти [orange] сталь [] із вхідного заліза, використовуючи вугілля як паливо. -tutorial.tunnelExplain.text = Також зауважте, що елементи проходять через [yellow] тунельний блок [] і з'являються з іншого боку, проходячи через кам'яний блок. Майте на увазі, що тунелі можуть проходити лише до 2 блоків. -tutorial.end.text = Ви завершили підручник! Удачі! -text.keybind.title = Ключ перемотки -keybind.move_x.name = move_x -keybind.move_y.name = move_y -keybind.select.name = Вибрати -keybind.break.name = {0}break{/0}{1}; {/1} -keybind.shoot.name = Постріл -keybind.zoom_hold.name = zoom_hold -keybind.zoom.name = Збільшити -keybind.block_info.name = Інформація про блок -keybind.menu.name = Меню -keybind.pause.name = Пауза -keybind.dash.name = Тире -keybind.chat.name = Чат -keybind.player_list.name = Список гравців -keybind.console.name = // Консоль 1 -keybind.rotate_alt.name = rotate_alt -keybind.rotate.name = Повернути -keybind.weapon_1.name = Зброя! -keybind.weapon_2.name = Зброя! -keybind.weapon_3.name = Зброя! -keybind.weapon_4.name = Зброя! -keybind.weapon_5.name = Зброя! -keybind.weapon_6.name = Зброя! -mode.waves.name = Хвилі -mode.sandbox.name = Пісочниця -mode.freebuild.name = Вільний режим -upgrade.standard.name = Стандартний -upgrade.standard.description = Стандартний механ. -upgrade.blaster.name = Бластер -upgrade.blaster.description = Стріляє повільно, слабкі кулі. -upgrade.triblaster.name = Трипластер -upgrade.triblaster.description = Вистрілює 3 кулі в розповсюдженні. -upgrade.clustergun.name = Касетна гармата -upgrade.clustergun.description = Вистрілює неточними вибуховими гранатами. -upgrade.beam.name = Пушечна гармата -upgrade.beam.description = Вистрілює далекобійним,пробірний лазерний промінь. -upgrade.vulcan.name = Вулкан -upgrade.vulcan.description = Вистрілює шквал швидких куль. -upgrade.shockgun.name = Шок-пушка -upgrade.shockgun.description = Стріляє руйнівним вибухом заряженої шрапнелі. -item.stone.name = Камінь -item.iron.name = Залізо -item.coal.name = Вугівалля -item.steel.name = Сталь -item.titanium.name = Титан -item.dirium.name = Дириум -item.thorium.name = Уран -item.sand.name = Пісок -liquid.water.name = Вода -liquid.plasma.name = Плазма -liquid.lava.name = Лава -liquid.oil.name = Нафта -block.weaponfactory.name = Фабрика зброї -block.weaponfactory.fulldescription = Використовується для створення зброї для гравця mech. Натисніть, щоб використати. Автоматично приймає ресурси з основного ядра. -block.air.name = Повітря -block.blockpart.name = Блокчастина -block.deepwater.name = Глибока вода -block.water.name = Вода -block.lava.name = Лава -block.oil.name = Нафта -block.stone.name = Камінь -block.blackstone.name = Чорний камінь -block.iron.name = Залізо -block.coal.name = Вугілля -block.titanium.name = Титан -block.thorium.name = Уран -block.dirt.name = Бруд -block.sand.name = Пісок -block.ice.name = Лід -block.snow.name = Сніг -block.grass.name = Трава -block.sandblock.name = Блок піску -block.snowblock.name = Блок снігу -block.stoneblock.name = Блок камню -block.blackstoneblock.name = Блок чорного камню -block.grassblock.name = Блок бруду -block.mossblock.name = Моссблок -block.shrub.name = Чагарник -block.rock.name = Камень -block.icerock.name = Ледяний камень -block.blackrock.name = Чорний камінь -block.dirtblock.name = Блок землі -block.stonewall.name = Кам'яна стіна -block.stonewall.fulldescription = Недорогий захисний блок. Корисно для захисту ядра та турелі в перші кілька хвиль. -block.ironwall.name = Залізна стіна -block.ironwall.fulldescription = Основний захисний блок. Забезпечує захист від ворогів. -block.steelwall.name = Сталева стіна -block.steelwall.fulldescription = Стандартний захисний блок. адекватний захист від ворогів. -block.titaniumwall.name = Титанова стіна -block.titaniumwall.fulldescription = Сильний захисний блок. Забезпечує захист від ворогів. -block.duriumwall.name = Діріумова стіна -block.duriumwall.fulldescription = Дуже сильний захисний блок. Забезпечує захист від ворогів. -block.compositewall.name = Композитна стіна -block.steelwall-large.name = Велика сталева стіна -block.steelwall-large.fulldescription = Стандартний захисний блок. Поєднує в собі кілька блоків. -block.titaniumwall-large.name = Велика титанова стіна -block.titaniumwall-large.fulldescription = Сильний захисний блок. Поєднує в собі кілька блоків. -block.duriumwall-large.name = Велика дирмітова стіна -block.duriumwall-large.fulldescription = Дуже сильний захисний блок.Поєднує в собі кілька блоків. -block.titaniumshieldwall.name = Стіна з щитом -block.titaniumshieldwall.fulldescription = Сильний захисний блок з додатковим вбудованим щитом. Потрібна енергія. Використовує енергію для поглинання ворожих куль. Рекомендується використовувати силові пристосування для забезпечення енергії цього блоку. -block.repairturret.name = Ремонтна турель -block.repairturret.fulldescription = Ремонтує недалекі пошкодженні блоки.Повільний темп. Використовує невелику кількість енергії. -block.megarepairturret.name = Ремонтна турель II -block.megarepairturret.fulldescription = Ремонтує недалекі пошкодженні блоки.Збільшений радіус та швидший темп ремонту . Використовує багато енергії. -block.shieldgenerator.name = Генератор щиту -block.shieldgenerator.fulldescription = Передовий захисний блок. Захищає всі блоки в радіусі від нападу. Не вкористовує енергію при бездіяльності, але швидко витрачає енергію на захист від куль. -block.door.name = Двері -block.door.fulldescription = Блок, який можна відкрити та закрити, торкнувшись його. -block.door-large.name = Великі двері -block.door-large.fulldescription = Блок, який можна відкрити та закрити, торкнувшись його. -block.conduit.name = Трубопровід -block.conduit.fulldescription = Основний транспортний блок. Працює як конвеєр, але з рідинами. Найкраще використовується з насосами або іншими трубопроводами. Може використовуватися як міст через рідини для ворогів та гравців. -block.pulseconduit.name = Імпульсний канал -block.pulseconduit.fulldescription = Покращенний блок перевезення рідин. Транспортує рідини швидше і зберігає більше стандартних каналів. -block.liquidrouter.name = маршрутизатор для рідини -block.liquidrouter.fulldescription = Працює аналогічно маршрутизатору. Приймає рідину ввід з одного боку і виводить його на інші сторони. Корисний для розщеплення рідини з одного каналу на кілька інших трубопроводів. -block.conveyor.name = Конвеєр -block.conveyor.fulldescription = Базовий транспортний блок. Переміщує предмети вперед і автоматично вкладає їх у турелі або ремісники. Поворотний Може використовуватися як міст через рідину для ворогів та гравців. -block.steelconveyor.name = Сталевий конвеєр -block.steelconveyor.fulldescription = Розширений блок транспортування предметів. Переміщення елементів швидше, ніж стандартні конвеєри. -block.poweredconveyor.name = Імпульсний конвеєр -block.poweredconveyor.fulldescription = Кінцевий транспортний блок. Переміщення елементів швидше, ніж сталеві конвеєри. -block.router.name = Маршрутизатор -block.router.fulldescription = Приймає елементи з одного напрямку і виводить їх на 3 інших напрямках. Можна також зберігати певну кількість предметів. Використовується для розщеплення матеріалів з одного свердла на декілька башточок. -block.junction.name = Міст -block.junction.fulldescription = Виступає як міст для двох перехресних конвеєрних стрічок. Корисне у ситуаціях з двома різними конвеєрами, що несуть різні матеріали в різних місцях. -block.conveyortunnel.name = Конвеєрний тунель -block.conveyortunnel.fulldescription = Транспортує предмети під блоками. Щоб використати, помістіть один тунель, що веде у блок, щоб бути підсвіченим, а один - з іншого боку. Переконайтеся, що обидва тунелі стикаються з протилежними напрямками, тобто до блоків, які вони вводять або виводять. -block.liquidjunction.name = Міст для рідини -block.liquidjunction.fulldescription = Діє як міст для двох перехресних трубопроводів. Корисно в ситуаціях з двома різними трубами, що несуть різні рідини в різних місцях. -block.liquiditemjunction.name = Перехрестя рідкого пункту -block.liquiditemjunction.fulldescription = Виступає як міст для перетину трубопроводів і конвеєрів. -block.powerbooster.name = Підсилювач потужності -block.powerbooster.fulldescription = Поширює енергію на всі блоки в межах його радіуса. -block.powerlaser.name = Енергетичний лазер -block.powerlaser.fulldescription = Створює лазер, який передає енергію блоку перед ним. Не створює жодної сили сама. Найкраще використовується з генераторами або іншими лазерами. -block.powerlaserrouter.name = Лазерний маршрутизатор -block.powerlaserrouter.fulldescription = Лазер, який розподіляє енергію у три напрямки одночасно. Корисно в ситуаціях, коли потрібно живити кілька блоків від одного генератора. -block.powerlasercorner.name = Лазерний кут -block.powerlasercorner.fulldescription = Лазер, який розподіляє енергію одночасно на два напрямки. Корисно в ситуаціях, коли потрібно живити кілька блоків від одного генератора, а маршрутизатор неточний. -block.teleporter.name = Телепорт -block.teleporter.fulldescription = Продвинутий блок транспортування предметів.Щоб телепортувати предмети з одного місця в інше потрібно збудувати 2 телепорти і назначити на них одинаковий колір. Використовує енергію. Натисніть, щоб змінити колір. -block.sorter.name = Сортувальник -block.sorter.fulldescription = Сортує предмети за типом матеріалу. Матеріал для прийняття позначається кольором у блоці. Всі елементи, що відповідають матеріалу сортування, виводяться вперед, а все інше виводить ліворуч і праворуч. -block.core.name = Ядро -block.pump.name = Насос -block.pump.fulldescription = Насоси рідини з вихідного блоку - зазвичай вода, лава чи олія. Виводить рідину в сусідні трубопроводи. -block.fluxpump.name = Флюсовий насос -block.fluxpump.fulldescription = Розширений варіант насоса. Зберігає більше рідини та перекачує швидше. -block.smelter.name = Плавильня -block.smelter.fulldescription = Основний ремісничий блок. Коли вводиться 1 залізо та 1 вугілля в якості палива, виводить одну сталь. Рекомендується вводити залізо та вугілля на різних поясах, щоб запобігти засміченню. -block.crucible.name = Тигель -block.crucible.fulldescription = Розширений блок обробки. При введенні 1 титану, 1 сталі та 1 вугілля в якості пального, виводить один дирний. Рекомендується вводити вугілля, сталь та титан на різних поясах, щоб запобігти засміченню. -block.coalpurifier.name = вугільний екстрактор -block.coalpurifier.fulldescription = Основний екстрактор. Виходить вугілля при постачанні великої кількості води та каменю. -block.titaniumpurifier.name = Титановий екстрактор -block.titaniumpurifier.fulldescription = Стандартний блок екстрактора. Виходить титан при постачанні великої кількості води та заліза. -block.oilrefinery.name = Нафтопереробний завод -block.oilrefinery.fulldescription = Очищує велику кількість нафти і перетворює на вугілля. Корисний для заправки вугільних башточок, коли вугільні родовища є дефіцитними. -block.stoneformer.name = Кам'янний екстрактор -block.stoneformer.fulldescription = Здавлюється рідка лава в камінь. Корисно для виготовлення великої кількості каменю для очищувачів вугілля. -block.lavasmelter.name = Лавовий завод -block.lavasmelter.fulldescription = Використовує лаву для перетворення залізо на сталь. Альтернатива плавильні. Корисно в ситуаціях, коли вугілля є дефіцитним. -block.stonedrill.name = Кам'янна свердловина -block.stonedrill.fulldescription = Основна свердловина.Розміщюється на кам'яній плитці виводить камінь повільними темпами. -block.irondrill.name = Залізна свердловина -block.irondrill.fulldescription = Базова свердловина.Розміщюється на родовищі залізної руди, випускає залізо в повільному темпі. -block.coaldrill.name = Вугільна свердловина -block.coaldrill.fulldescription = Базова свердловина.Розміщюється на родовищі вугільної руди ,видобуває вугілля повільними темпами. -block.thoriumdrill.name = Уранова свердловина -block.thoriumdrill.fulldescription = Продвинута свердловина. Розміщюється на родовищі уранової руди.Видобуток урану відбувається повільними темпами. -block.titaniumdrill.name = Титанова свердловина -block.titaniumdrill.fulldescription = Продвинута свердловина.Розміщюється на родовищі титанової руди, Видобуток титану відбувається повільним темпом. -block.omnidrill.name = Убер свердловина -block.omnidrill.fulldescription = Кінцева свердловина.Дуже швидко видобуває будь-який вид руди. -block.coalgenerator.name = Вугільний генератор -block.coalgenerator.fulldescription = Основний генератор. Генерує енергію з вугілля. Виводиться потужність лазерів на 4 сторони. -block.thermalgenerator.name = Теплогенератор -block.thermalgenerator.fulldescription = Генерує енергію від лави. Виводиться потужність лазерів на 4 сторони. -block.combustiongenerator.name = Генератор горіння -block.combustiongenerator.fulldescription = Генерує енергію з нафти. Виводиться потужність лазерів на 4 сторони. -block.rtgenerator.name = RTG генератор -block.rtgenerator.fulldescription = Генерує невелику кількість енергії з радіоактивного розпаду урану. Виводиться потужність лазерів на 4 сторони. -block.nuclearreactor.name = Ядерний реактор -block.nuclearreactor.fulldescription = Розширений варіант RTG Generator і кінцевий генератор електроенергії. Генерує енергію з урану. Потребує постійного водяного охолодження.Сильно вибухне якщо не буде постачання води у великії кількості -block.turret.name = Турель -block.turret.fulldescription = Базова, дешева турель. Використовує камінь для боєприпасів. Має трохи більше діапазону, ніж подвійна турель. -block.doubleturret.name = Подвійна турель -block.doubleturret.fulldescription = Дещо потужна версія турель. Використовує камінь для боєприпасів. Значно більший урон, але менший діапазон. Вистрілює дві кулі. -block.machineturret.name = Кулеметна турель -block.machineturret.fulldescription = Стандартна всеосяжна турель. Використовує залізо для боєприпасів. Має швидку швидкість пострілу і гідну шкоду. -block.shotgunturret.name = Розріджуюча турель -block.shotgunturret.fulldescription = Стандартна турель. Використовує залізо для боєприпасів. Вистрілює 7 куль навколо себе.Наносить значних ушкоджень,звісно якщо поцілить :) -block.flameturret.name = Вогнемет -block.flameturret.fulldescription = Продвинута турель ближнього діапазону. Використовує вугілля для боєприпасів. Має дуже низький радіус, але дуже високий збиток. Добре для близьких дистанцій. Рекомендується використовувати за стінами. -block.sniperturret.name = Лазерна турель. -block.sniperturret.fulldescription = Продвинута далекобійна турель. Використовує сталь для боєприпасів. Дуже високий збиток, але низький рівень урону. Дорогі для використання, але можуть бути розташовані далеко від ліній ворога через його радіус. -block.mortarturret.name = Флак турель -block.mortarturret.fulldescription = Продвинута,неточна турель. Використовує вугілля для боєприпасів. Стріляє кулями, що вибухають у шрапнеллв. Корисне для великих натовпів ворогів. -block.laserturret.name = Лазерна турель -block.laserturret.fulldescription = Продвинута однопушечна турель. Використовує енергію. Хороша на середніх дистанціях. Ніколи не пропускає. -block.waveturret.name = Тесла -block.waveturret.fulldescription = Передова багатоцільова турель. Використовує енергію. Середній радіус. Ніколи не пропускає. Активно знижує, але може вражати декількох ворогів одночасно з ланцюговим освітленням. -block.plasmaturret.name = Плазмова турель -block.plasmaturret.fulldescription = Дуже продвинута версія Вогнеметної турелі. Використовує вугілля як боєприпаси. Дуже високий урон, від близької до середньої дистанції. -block.chainturret.name = Уранова турель -block.chainturret.fulldescription = Остаточна швидкістна вежа. Використовує уран як боєприпаси. Вистрілює великі кулі при високій швидкості вогню. Середній радіус. Промінь кілька плиток. Надзвичайно жорсткий. -block.titancannon.name = Титанова гармата -block.titancannon.fulldescription = Найбільш далекобійна турель. Використовує уран як боєприпаси. Вистрілює великі снаряди. Далекобійний. Промінь кілька плиток. Надзвичайно жорсткий. -block.playerspawn.name = Спавн Гравця -block.enemyspawn.name = Спавн ворогів +text.quit=Вийти +text.about.button=Про +text.name=Назва: +text.players={0} гравців онлайн +text.players.single={0} гравців онлайн +text.server.mismatch=Пакетна помилка: невідповідність версії версії клієнта / сервера. Переконайтеся, що ви та хост мають останню версію Mindustry! +text.server.closing=[accent] Закриття сервера ... +text.server.kicked.kick=Ви були вигнані з сервера! +text.server.kicked.invalidPassword=Невірний пароль! +text.server.kicked.clientOutdated=Застарілий клієнт! Оновіть свою гру! +text.server.kicked.serverOutdated=Застарілий сервер! Попросіть хост оновити! +text.server.connected={0} приєднався. +text.server.disconnected={0} від'єднано. +text.nohost=Неможливо розмістити сервер на власній карті! +text.hostserver=Хост-сервер +text.host=Хост +text.hosting=[accent] Відкриття сервера ... +text.hosts.refresh=Оновити +text.hosts.discovering=Знайомство з мережевими іграми +text.server.refreshing=Оновити сервери +text.hosts.none=[lightgray] Ніяких ігор у мережі не знайдено! +text.host.invalid=[scarlet] Неможливо підключитися до хосту. +text.server.friendlyfire=Дружній вогонь +text.server.add=Додати сервер +text.server.delete=Ви впевнені, що хочете видалити цей сервер? +text.server.hostname=Хост: {0} +text.server.edit=Редагувати сервер +text.joingame.title=Приєднатися до гри +text.joingame.ip=IP +text.disconnect=Роз'єднано +text.connecting=[accent] Підключення ... +text.connecting.data=[accent] Завантаження світових даних ... +text.connectfail=[crimson] Не вдалося підключитися до сервера: [orange] {0} +text.server.port=Порт +text.server.addressinuse=Адреса вже використовується! +text.server.invalidport=Недійсний номер порту. +text.server.error=[crimson] Помилка хостингу сервера: [orange] {0} +text.save.new=Нове збереження +text.save.overwrite=Ви впевнені, що хочете перезаписати цей слот для збереження? +text.overwrite=Перезаписати +text.save.none=Не знайдено жодних збережень! +text.saveload=[accent] Збереження ... +text.savefail=Не вдалося зберегти гру! +text.save.delete.confirm=Ви впевнені, що хочете видалити це збереження? +text.save.delete=Видалити +text.save.export=Експорт збереження +text.save.import.invalid=[orange] Це збереження недійсне! +text.save.import.fail=[crimson] Не вдалося імпортувати збереження: [orange] {0} +text.save.export.fail=[crimson] Не вдалося експортувати збереження: [orange] {0} +text.save.import=Імпортувати збереження +text.save.newslot=Назва збереження: +text.save.rename=Переіменувати +text.save.rename.text=Нова назва: +text.selectslot=Виберіть збереження. +text.slot=[accent] слот {0} +text.save.corrupted=[orange] Збережений файл пошкоджений або він невірний! +text.empty=<порожньо> +text.on=Увімкнути +text.off=Вимкнути +text.save.autosave=Автозбереження: {0} +text.save.map=Карта +text.save.wave=Хвиля {0} +text.save.difficulty=Складність +text.save.date=Останнє збережено: {0} +text.confirm=Підтвердити +text.delete=Видалити +text.ok=ОК +text.open=Відкрити +text.cancel=Скасувати +text.openlink=Відкрити посилання +text.back=Назад +text.quit.confirm=Ти впевнений що хочеш піти? +text.loading=[accent] Завантаження ... +text.wave=[orange] хвиля {0} +text.wave.waiting=Хвиля через {0} +text.waiting=Очікування… +text.enemies={0} Вороги +text.enemies.single=Противник +text.loadimage=Завантажити зображення +text.saveimage=Зберегти зображення +text.editor.badsize=[orange] Недійсні розміри зображення! [] Дійсні розміри карти: {0} +text.editor.errorimageload=Помилка завантаження файлу зображень: [orange] {0} +text.editor.errorimagesave=Помилка збереження файлу зображення: [orange] {0} +text.editor.generate=Генератор +text.editor.resize=Змінити розмір +text.editor.loadmap=// Завантажити карту +text.editor.savemap=Зберегти карту +text.editor.loadimage=Завантажити зображення +text.editor.saveimage=Зберегти зображення +text.editor.unsaved=[scarlet] У вас є незбережені зміни! [] Ви впевнені, що хочете вийти? +text.editor.resizemap=Змінити розмір карти +text.editor.mapname=Назва карти: +text.editor.overwrite=[accent] Попередження! Це перезаписує існуючу карту. +text.editor.selectmap=Виберіть карту для завантаження: +text.width=Ширина +text.height=Висота +text.menu=Меню +text.play=Відтворити +text.load=Завантаження +text.save=Зберегти +text.language.restart=Будь ласка, перезапустіть свою гру, щоб налаштування мови набули чинності. +text.settings.language=Мова +text.settings=Налаштування +text.tutorial=Навчальний\nпосібник +text.editor=Редактор +text.mapeditor=Редактор карт +text.donate=Підтримати проект +text.settings.reset=Скинути до стандартних +text.settings.controls=Елементи управління +text.settings.game=Гра +text.settings.sound=Звук +text.settings.graphics=Графіка +text.upgrades=Оновлення +text.purchased=[LIME] Створено! +text.weapons=Зброя +text.paused=Пауза +text.info.title=[accent] інформація +text.error.title=[crimson] Виникла помилка +text.error.crashtitle=Виникла помилка +text.blocks.blockinfo=Блокування інформації +text.blocks.powercapacity=Потужність +text.blocks.powershot=Потужність / постріл +text.blocks.size=Розмір +text.blocks.liquidcapacity=Ємкість рідини +text.blocks.maxitemssecond=Макс. Елементи / секунду +text.blocks.powerrange=Радіус потужності +text.blocks.itemcapacity=Ємкість предмету +text.blocks.inputliquid=Ввід речовини +text.blocks.inputitem=Вхідний матеріал +text.blocks.explosive=Вибухонебезпечний! +text.blocks.health=Здоров'я +text.blocks.inaccuracy=Неточність +text.blocks.shots=Постріли +text.blocks.inputcapacity=Вхідна ємність +text.blocks.outputcapacity=Випускна ємність +setting.difficulty.easy=Легкий +setting.difficulty.normal=Нормальний +setting.difficulty.hard=Важкий +setting.difficulty.insane=Божевільний +setting.difficulty.purge=Очистити +setting.difficulty.name=Складність +setting.screenshake.name=Тряска екрана +setting.indicators.name=Індикатори ворога +setting.effects.name=Ефекти відображення +setting.sensitivity.name=Чутливість контролера +setting.saveinterval.name=Інтервал автозбереження +setting.seconds={0} секунд +setting.fullscreen.name=Повноекранний +setting.multithread.name=Багатопотоковий [scarlet] (нестабільний!) +setting.fps.name=Показати FPS +setting.vsync.name=VSunc +setting.lasers.name=Показати енергетичні лазери +setting.healthbars.name=Показати здоров'я +setting.musicvol.name=Гучність музики +setting.mutemusic.name=Вимкнути музику +setting.sfxvol.name=Гучність ефектів +setting.mutesound.name=Вимкнути звук +map.maze.name=Лабіринт +map.fortress.name=Фортеця +map.sinkhole.name=Свердловина +map.caves.name=Печери +map.volcano.name=Вулкан +map.caldera.name=Кальдера +map.scorch.name=Мертва земля +map.desert.name=Пустеля +map.island.name=Острів +map.grassland.name=Пасовища +map.tundra.name=Тундра +map.spiral.name=Спіраль +map.tutorial.name=Навчання +text.keybind.title=Ключ перемотки +keybind.move_x.name=move_x +keybind.move_y.name=move_y +keybind.select.name=Вибрати +keybind.break.name={0}break{/0}{1}; {/1} +keybind.shoot.name=Постріл +keybind.zoom_hold.name=zoom_hold +keybind.zoom.name=Збільшити +keybind.block_info.name=Інформація про блок +keybind.menu.name=Меню +keybind.pause.name=Пауза +keybind.dash.name=Тире +keybind.chat.name=Чат +keybind.player_list.name=Список гравців +keybind.console.name=// Консоль 1 +keybind.rotate_alt.name=rotate_alt +keybind.rotate.name=Повернути +mode.waves.name=Хвилі +mode.sandbox.name=Пісочниця +mode.freebuild.name=Вільний режим +item.stone.name=Камінь +item.coal.name=Вугівалля +item.titanium.name=Титан +item.thorium.name=Уран +item.sand.name=Пісок +liquid.water.name=Вода +liquid.lava.name=Лава +liquid.oil.name=Нафта +block.door.name=Двері +block.door-large.name=Великі двері +block.conduit.name=Трубопровід +block.pulseconduit.name=Імпульсний канал +block.liquidrouter.name=маршрутизатор для рідини +block.conveyor.name=Конвеєр +block.router.name=Маршрутизатор +block.junction.name=Міст +block.liquidjunction.name=Міст для рідини +block.sorter.name=Сортувальник +block.smelter.name=Плавильня +text.credits=Credits +text.link.discord.description=the official Mindustry discord chatroom +text.link.github.description=Game source code +text.link.dev-builds.description=Unstable development builds +text.link.trello.description=Official trello board for planned features +text.link.itch.io.description=itch.io page with PC downloads and web version +text.link.google-play.description=Google Play store listing +text.link.wiki.description=official Mindustry wiki +text.linkfail=Failed to open link!\nThe URL has been copied to your cliboard. +text.editor.web=The web version does not support the editor!\nDownload the game to use it. +text.web.unsupported=The web version does not support this feature! Download the game to use it. +text.multiplayer.web=This version of the game does not support multiplayer!\nTo play multiplayer from your browser, use the "multiplayer web version" link at the itch.io page. +text.host.web=The web version does not support hosting games! Download the game to use this feature. +text.map.delete=Are you sure you want to delete the map "[orange]{0}[]"? +text.construction.title=Block Construction Guide +text.construction=You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. +text.deconstruction.title=Block Deconstruction Guide +text.deconstruction=You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. +text.showagain=Don't show again next session +text.unlocks=Unlocks +text.addplayers=Add/Remove Players +text.maps=Maps +text.maps.none=[LIGHT_GRAY]No maps found! +text.unlocked=New Block Unlocked! +text.unlocked.plural=New Blocks Unlocked! +text.server.kicked.fastShoot=You are shooting too quickly. +text.server.kicked.banned=You are banned on this server. +text.server.kicked.recentKick=You have been kicked recently.\nWait before connecting again. +text.server.kicked.nameInUse=There is someone with that name\nalready on this server. +text.server.kicked.nameEmpty=Your name must contain at least one character or number. +text.server.kicked.idInUse=You are already on this server! Connecting with two accounts is not permitted. +text.server.kicked.customClient=This server does not support custom builds. Download an official version. +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +text.trace=Trace Player +text.trace.playername=Player name: [accent]{0} +text.trace.ip=IP: [accent]{0} +text.trace.id=Unique ID: [accent]{0} +text.trace.android=Android Client: [accent]{0} +text.trace.modclient=Custom Client: [accent]{0} +text.trace.totalblocksbroken=Total blocks broken: [accent]{0} +text.trace.structureblocksbroken=Structure blocks broken: [accent]{0} +text.trace.lastblockbroken=Last block broken: [accent]{0} +text.trace.totalblocksplaced=Total blocks placed: [accent]{0} +text.trace.lastblockplaced=Last block placed: [accent]{0} +text.invalidid=Invalid client ID! Submit a bug report. +text.server.bans=Bans +text.server.bans.none=No banned players found! +text.server.admins=Admins +text.server.admins.none=No admins found! +text.server.outdated=[crimson]Outdated Server![] +text.server.outdated.client=[crimson]Outdated Client![] +text.server.version=[lightgray]Version: {0} +text.server.custombuild=[yellow]Custom Build +text.confirmban=Are you sure you want to ban this player? +text.confirmunban=Are you sure you want to unban this player? +text.confirmadmin=Are you sure you want to make this player an admin? +text.confirmunadmin=Are you sure you want to remove admin status from this player? +text.disconnect.data=Failed to load world data! +text.copylink=Copy Link +text.changelog.title=Changelog +text.changelog.loading=Getting changelog... +text.changelog.error.android=[orange]Note that the changelog sometimes does not work on Android 4.4 and below!\nThis is due to an internal Android bug. +text.changelog.error.ios=[orange]The changelog is currently not supported in iOS. +text.changelog.error=[scarlet]Error getting changelog!\nCheck your internet connection. +text.changelog.current=[yellow][[Current version] +text.changelog.latest=[orange][[Latest version] +text.saving=[accent]Saving... +text.unknown=Unknown +text.custom=Custom +text.builtin=Built-In +text.map.delete.confirm=Are you sure you want to delete this map? This action cannot be undone! +text.map.random=[accent]Random Map +text.map.nospawn=This map does not have any cores for the player to spawn in! Add a [ROYAL]blue[] core to this map in the editor. +text.editor.slope=\\ +text.editor.openin=Open In Editor +text.editor.oregen=Ore Generation +text.editor.oregen.info=Ore Generation: +text.editor.mapinfo=Map Info +text.editor.author=Author: +text.editor.description=Description: +text.editor.name=Name: +text.editor.teams=Teams +text.editor.elevation=Elevation +text.editor.saved=Saved! +text.editor.save.noname=Your map does not have a name! Set one in the 'map info' menu. +text.editor.save.overwrite=Your map overwrites a built-in map! Pick a different name in the 'map info' menu. +text.editor.import.exists=[scarlet]Unable to import:[] a built-in map named '{0}' already exists! +text.editor.import=Import... +text.editor.importmap=Import Map +text.editor.importmap.description=Import an already existing map +text.editor.importfile=Import File +text.editor.importfile.description=Import an external map file +text.editor.importimage=Import Terrain Image +text.editor.importimage.description=Import an external map image file +text.editor.export=Export... +text.editor.exportfile=Export File +text.editor.exportfile.description=Export a map file +text.editor.exportimage=Export Terrain Image +text.editor.exportimage.description=Export a map image file +text.editor.overwrite.confirm=[scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +text.fps=FPS: {0} +text.tps=TPS: {0} +text.ping=Ping: {0}ms +text.settings.rebind=Rebind +text.yes=Yes +text.no=No +text.blocks.targetsair=Targets Air +text.blocks.itemspeed=Units Moved +text.blocks.shootrange=Range +text.blocks.poweruse=Power Use +text.blocks.inputitemcapacity=Input Item Capacity +text.blocks.outputitemcapacity=Input Item Capacity +text.blocks.maxpowergeneration=Max Power Generation +text.blocks.powertransferspeed=Power Transfer +text.blocks.craftspeed=Production Speed +text.blocks.inputliquidaux=Aux Liquid +text.blocks.inputitems=Input Items +text.blocks.outputitem=Output Item +text.blocks.drilltier=Drillables +text.blocks.drillspeed=Base Drill Speed +text.blocks.liquidoutput=Liquid Output +text.blocks.liquiduse=Liquid Use +text.blocks.coolant=Coolant +text.blocks.coolantuse=Coolant Use +text.blocks.inputliquidfuel=Fuel Liquid +text.blocks.liquidfueluse=Liquid Fuel Use +text.blocks.reload=Reload +text.blocks.inputfuel=Fuel +text.blocks.fuelburntime=Fuel Burn Time +text.unit.blocks=blocks +text.unit.powersecond=power units/second +text.unit.liquidsecond=liquid units/second +text.unit.itemssecond=items/second +text.unit.pixelssecond=pixels/second +text.unit.liquidunits=liquid units +text.unit.powerunits=power units +text.unit.degrees=degrees +text.unit.seconds=seconds +text.unit.none= +text.unit.items=items +text.category.general=General +text.category.power=Power +text.category.liquids=Liquids +text.category.items=Items +text.category.crafting=Crafting +text.category.shooting=Shooting +setting.minimap.name=Show Minimap +mode.text.help.title=Description of modes +mode.waves.description=the normal mode. limited resources and automatic incoming waves. +mode.sandbox.description=infinite resources and no timer for waves. +mode.freebuild.description=limited resources and no timer for waves. +content.item.name=Items +content.liquid.name=Liquids +content.unit-type.name=Units +content.recipe.name=Blocks +item.stone.description=A common raw material. Used for separating and refining into other materials, or melting into lava. +item.tungsten.name=Tungsten +item.tungsten.description=A common, but very useful structure material. Used in drills and heat-resistant blocks such as generators and smelteries. +item.lead.name=Lead +item.lead.description=A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.coal.description=A common and readily available fuel. +item.carbide.name=Carbide +item.carbide.description=A tough alloy made with tungsten and carbon. Used in advanced transportation blocks and high-tier drills. +item.titanium.description=A rare super-light metal used extensively in liquid transportation, drills and aircraft. +item.thorium.description=A dense, radioactive metal used as structural support and nuclear fuel. +item.silicon.name=Silicon +item.silcion.description=An extremely useful semiconductor, with applications in solar panels and many complex electronics. +item.plastanium.name=Plastanium +item.plastanium.description=A light, ductile material used in advanced aircraft and fragmentation ammunition. +item.phase-matter.name=Phase Matter +item.surge-alloy.name=Surge Alloy +item.biomatter.name=Biomatter +item.biomatter.description=A clump of organic mush; used for conversion into oil or as a basic fuel. +item.sand.description=A common material that is used extensively in smelting, both in alloying and as a flux. +item.blast-compound.name=Blast Compound +item.blast-compound.description=A volatile compound used in bombs and explosives. While it can burned as fuel, this is not advised. +item.pyratite.name=Pyratite +item.pyratite.description=An extremely flammable substance used in incendiary weapons. +liquid.cryofluid.name=Cryofluid +text.item.explosiveness=[LIGHT_GRAY]Explosiveness: {0} +text.item.flammability=[LIGHT_GRAY]Flammability: {0} +text.item.radioactivity=[LIGHT_GRAY]Radioactivity: {0} +text.item.fluxiness=[LIGHT_GRAY]Flux Power: {0} +text.item.hardness=[LIGHT_GRAY]Hardness: {0} +text.liquid.heatcapacity=[LIGHT_GRAY]Heat Capacity: {0} +text.liquid.viscosity=[LIGHT_GRAY]Viscosity: {0} +text.liquid.temperature=[LIGHT_GRAY]Temperature: {0} +block.tungsten-wall.name=Tungsten Wall +block.tungsten-wall-large.name=Large Tungsten Wall +block.carbide-wall.name=Carbide Wall +block.carbide-wall-large.name=Large Carbide Wall +block.thorium-wall.name=Thorium Wall +block.thorium-wall-large.name=Large Thorium Wall +block.duo.name=Duo +block.scorch.name=Scorch +block.hail.name=Hail +block.lancer.name=Lancer +block.titanium-conveyor.name=Titanium Conveyor +block.splitter.name=Splitter +block.splitter.description=Outputs items into two opposite directions immediately after they are recieved. +block.router.description=Splits items into all 4 directions. Can store items as a buffer. +block.distributor.name=Distributor +block.distributor.description=A splitter that can split items into 8 directions. +block.sorter.description=Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. +block.overflow-gate.name=Overflow Gate +block.overflow-gate.description=A combination splitter and router that only outputs to the left and right if the front path is blocked. +block.bridgeconveyor.name=Bridge Conveyor +block.bridgeconveyor.description=A conveyor that can go over other blocks, for up to two total blocks. +block.arc-smelter.name=Arc Smelter +block.silicon-smelter.name=Silicon Smelter +block.phase-weaver.name=Phase Weaver +block.pulverizer.name=Pulverizer +block.cryofluidmixer.name=Cryofluid Mixer +block.melter.name=Melter +block.incinerator.name=Incinerator +block.biomattercompressor.name=Biomatter Compressor +block.separator.name=Separator +block.centrifuge.name=Centrifuge +block.power-node.name=Power Node +block.power-node-large.name=Large Power Node +block.battery.name=Battery +block.battery-large.name=Large Battery +block.combustion-generator.name=Combustion Generator +block.turbine-generator.name=Turbine Generator +block.tungsten-drill.name=Tungsten Drill +block.carbide-drill.name=Carbide Drill +block.laser-drill.name=Laser Drill +block.water-extractor.name=Water Extractor +block.cultivator.name=Cultivator +block.dart-ship-factory.name=Dart Ship Factory +block.delta-mech-factory.name=Delta Mech Factory +block.dronefactory.name=Drone Factory +block.repairpoint.name=Repair Point +block.resupplypoint.name=Resupply Point +block.liquidtank.name=Liquid Tank +block.bridgeconduit.name=Bridge Conduit +block.mechanical-pump.name=Mechanical Pump +block.itemsource.name=Item Source +block.itemvoid.name=Item Void +block.liquidsource.name=Liquid Source +block.powervoid.name=Power Void +block.powerinfinite.name=Power Infinite +block.unloader.name=Unloader +block.sortedunloader.name=Sorted Unloader +block.vault.name=Vault +block.wave.name=Wave +block.swarmer.name=Swarmer +block.salvo.name=Salvo +block.ripple.name=Ripple +block.phase-conveyor.name=Phase Conveyor +block.bridge-conveyor.name=Bridge Conveyor +block.plastanium-compressor.name=Plastanium Compressor +block.pyratite-mixer.name=Pyratite Mixer +block.blast-mixer.name=Blast Mixer +block.solidifer.name=Solidifer +block.solar-panel.name=Solar Panel +block.solar-panel-large.name=Large Solar Panel +block.oil-extractor.name=Oil Extractor +block.javelin-ship-factory.name=Javelin Ship factory +block.drone-factory.name=Drone Factory +block.fabricator-factory.name=Fabricator Factory +block.repair-point.name=Repair Point +block.resupply-point.name=Resupply Point +block.pulse-conduit.name=Pulse Conduit +block.phase-conduit.name=Phase Conduit +block.liquid-router.name=Liquid Router +block.liquid-tank.name=Liquid Tank +block.liquid-junction.name=Liquid Junction +block.bridge-conduit.name=Bridge Conduit +block.rotary-pump.name=Rotary Pump +block.nuclear-reactor.name=Nuclear Reactor +text.save.old=This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. diff --git a/core/assets/shaders/outline.fragment b/core/assets/shaders/outline.fragment index 1c6fdd5b28..46f6f6872d 100644 --- a/core/assets/shaders/outline.fragment +++ b/core/assets/shaders/outline.fragment @@ -3,6 +3,8 @@ precision mediump float; precision mediump int; #endif +#define SPACE 1.0 + uniform sampler2D u_texture; uniform vec4 u_color; @@ -11,30 +13,15 @@ uniform vec2 u_texsize; varying vec4 v_color; varying vec2 v_texCoord; -bool id(vec4 v){ - return v.a > 0.1; -} - void main() { - - vec2 T = v_texCoord.xy; - vec2 v = vec2(1.0/u_texsize.x, 1.0/u_texsize.y); - bool any = false; + vec4 c = texture2D(u_texture, v_texCoord.xy); - float step = 1.0; - - vec4 c = texture2D(u_texture, T); - - if(texture2D(u_texture, T).a < 0.1 && - (id(texture2D(u_texture, T + vec2(0, step) * v)) || id(texture2D(u_texture, T + vec2(0, -step) * v)) || - id(texture2D(u_texture, T + vec2(step, 0) * v)) || id(texture2D(u_texture, T + vec2(-step, 0) * v)))) - any = true; - - if(any){ - gl_FragColor = u_color; - }else{ - gl_FragColor = c * v_color; - } + gl_FragColor = mix(c * v_color, u_color, + (1.0-step(0.1, texture2D(u_texture, v_texCoord.xy).a)) * + step(0.1, texture2D(u_texture, v_texCoord.xy + vec2(0, SPACE) * v).a + + texture2D(u_texture, v_texCoord.xy + vec2(0, -SPACE) * v).a + + texture2D(u_texture, v_texCoord.xy + vec2(SPACE, 0) * v).a + + texture2D(u_texture, v_texCoord.xy + vec2(-SPACE, 0) * v).a)); } diff --git a/core/assets/sprites/sprites.atlas b/core/assets/sprites/sprites.atlas index 84ce8e37db..be782dff2f 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -13,42 +13,49 @@ background index: -1 bridge-conveyor-arrow rotate: false - xy: 333, 15 + xy: 333, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conveyor-bridge rotate: false - xy: 343, 25 + xy: 343, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conveyor-end rotate: false - xy: 333, 5 + xy: 353, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conveyor-arrow rotate: false - xy: 597, 128 + xy: 627, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conveyor-bridge rotate: false - xy: 587, 108 + xy: 637, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conveyor-end rotate: false - xy: 597, 118 + xy: 627, 108 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +router + rotate: false + xy: 647, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -90,21 +97,21 @@ blast-drill-top index: -1 carbide-drill rotate: false - xy: 343, 15 + xy: 343, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 carbide-drill-rotator rotate: false - xy: 353, 25 + xy: 353, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 carbide-drill-top rotate: false - xy: 343, 5 + xy: 363, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -188,21 +195,21 @@ plasma-drill-top index: -1 tungsten-drill rotate: false - xy: 670, 138 + xy: 741, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten-drill-rotator rotate: false - xy: 680, 139 + xy: 747, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten-drill-top rotate: false - xy: 677, 128 + xy: 747, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -272,14 +279,14 @@ block-icon-blackstone index: -1 blackstone2 rotate: false - xy: 974, 367 + xy: 512, 72 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 blackstone3 rotate: false - xy: 512, 83 + xy: 957, 359 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -293,35 +300,35 @@ blackstoneedge index: -1 coal1 rotate: false - xy: 353, 15 + xy: 353, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 coal2 rotate: false - xy: 363, 25 + xy: 363, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 coal3 rotate: false - xy: 353, 5 + xy: 373, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 dirt2 rotate: false - xy: 383, 25 + xy: 967, 356 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 dirt3 rotate: false - xy: 373, 5 + xy: 977, 356 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -335,42 +342,42 @@ dirtedge index: -1 grass-cliff-edge rotate: false - xy: 403, 25 + xy: 997, 345 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass-cliff-edge-1 rotate: false - xy: 403, 15 + xy: 1007, 349 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass-cliff-edge-2 rotate: false - xy: 403, 5 + xy: 1007, 339 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass-cliff-side rotate: false - xy: 517, 131 + xy: 409, 48 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass2 rotate: false - xy: 393, 15 + xy: 997, 355 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass3 rotate: false - xy: 393, 5 + xy: 987, 345 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -384,42 +391,42 @@ grassedge index: -1 ice-cliff-edge rotate: false - xy: 517, 101 + xy: 971, 336 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice-cliff-edge-1 rotate: false - xy: 967, 357 + xy: 413, 28 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice-cliff-edge-2 rotate: false - xy: 967, 347 + xy: 413, 18 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice-cliff-side rotate: false - xy: 977, 357 + xy: 413, 8 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice2 rotate: false - xy: 517, 121 + xy: 409, 38 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice3 rotate: false - xy: 517, 111 + xy: 961, 336 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -433,35 +440,35 @@ iceedge index: -1 icerock2 rotate: false - xy: 977, 347 + xy: 981, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 icerockshadow1 rotate: false - xy: 987, 355 + xy: 991, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 rockshadow1 rotate: false - xy: 987, 355 + xy: 991, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 icerockshadow2 rotate: false - xy: 997, 355 + xy: 701, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 rockshadow2 rotate: false - xy: 997, 355 + xy: 701, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -475,56 +482,56 @@ lavaedge index: -1 lead1 rotate: false - xy: 505, 171 + xy: 567, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 lead2 rotate: false - xy: 517, 181 + xy: 555, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 lead3 rotate: false - xy: 527, 181 + xy: 565, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor2 rotate: false - xy: 565, 171 + xy: 527, 131 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor3 rotate: false - xy: 522, 161 + xy: 542, 151 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor4 rotate: false - xy: 532, 161 + xy: 540, 141 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor5 rotate: false - xy: 542, 161 + xy: 527, 121 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor6 rotate: false - xy: 552, 161 + xy: 537, 131 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -545,49 +552,49 @@ oiledge index: -1 rock2 rotate: false - xy: 617, 108 + xy: 637, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand-cliff-edge rotate: false - xy: 637, 118 + xy: 657, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand-cliff-edge-1 rotate: false - xy: 647, 128 + xy: 657, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand-cliff-edge-2 rotate: false - xy: 637, 108 + xy: 657, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand-cliff-side rotate: false - xy: 647, 118 + xy: 657, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand2 rotate: false - xy: 637, 128 + xy: 662, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand3 rotate: false - xy: 627, 108 + xy: 660, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -601,49 +608,49 @@ sandedge index: -1 shrubshadow rotate: false - xy: 577, 98 + xy: 672, 149 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow-cliff-edge rotate: false - xy: 607, 98 + xy: 667, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow-cliff-edge-1 rotate: false - xy: 617, 98 + xy: 667, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow-cliff-edge-2 rotate: false - xy: 627, 98 + xy: 667, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow-cliff-side rotate: false - xy: 637, 98 + xy: 670, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow2 rotate: false - xy: 587, 98 + xy: 682, 149 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow3 rotate: false - xy: 597, 98 + xy: 667, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -664,42 +671,42 @@ spaceedge index: -1 stone-cliff-edge rotate: false - xy: 662, 148 + xy: 677, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone-cliff-edge-1 rotate: false - xy: 660, 138 + xy: 677, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone-cliff-edge-2 rotate: false - xy: 657, 128 + xy: 677, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone-cliff-side rotate: false - xy: 657, 118 + xy: 889, 317 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone2 rotate: false - xy: 647, 98 + xy: 680, 139 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone3 rotate: false - xy: 662, 158 + xy: 677, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -713,91 +720,91 @@ stoneedge index: -1 thorium1 rotate: false - xy: 657, 108 + xy: 736, 241 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 thorium2 rotate: false - xy: 657, 98 + xy: 736, 231 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 thorium3 rotate: false - xy: 672, 159 + xy: 736, 221 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 titanium1 rotate: false - xy: 682, 159 + xy: 736, 211 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 titanium2 rotate: false - xy: 672, 149 + xy: 731, 201 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 titanium3 rotate: false - xy: 682, 149 + xy: 731, 191 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten1 rotate: false - xy: 667, 118 + xy: 741, 191 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten2 rotate: false - xy: 667, 108 + xy: 737, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten3 rotate: false - xy: 667, 98 + xy: 737, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 water-cliff-edge rotate: false - xy: 677, 118 + xy: 751, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 water-cliff-edge-1 rotate: false - xy: 677, 108 + xy: 873, 305 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 water-cliff-edge-2 rotate: false - xy: 677, 98 + xy: 883, 305 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 water-cliff-side rotate: false - xy: 889, 317 + xy: 871, 295 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -811,63 +818,63 @@ wateredge index: -1 block-border rotate: false - xy: 957, 349 + xy: 931, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-elevation rotate: false - xy: 921, 335 + xy: 941, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 combustion-generator-top rotate: false - xy: 921, 335 + xy: 941, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-middle rotate: false - xy: 313, 15 + xy: 313, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 pump-liquid rotate: false - xy: 313, 15 + xy: 313, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-slope rotate: false - xy: 323, 25 + xy: 323, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 border rotate: false - xy: 313, 5 + xy: 333, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 conduit-liquid rotate: false - xy: 373, 25 + xy: 393, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 cross-1 rotate: false - xy: 373, 15 + xy: 512, 62 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -895,7 +902,7 @@ cross-4 index: -1 enemyspawn rotate: false - xy: 383, 5 + xy: 987, 355 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -909,21 +916,21 @@ nuclearreactor-shadow index: -1 place-arrow rotate: false - xy: 607, 128 + xy: 637, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 playerspawn rotate: false - xy: 597, 108 + xy: 647, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ripples rotate: false - xy: 488, 68 + xy: 416, 58 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -972,7 +979,7 @@ rubble-3-1 index: -1 shadow-1 rotate: false - xy: 428, 56 + xy: 452, 56 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -1014,7 +1021,7 @@ shadow-6 index: -1 shadow-round-1 rotate: false - xy: 440, 56 + xy: 464, 56 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -1035,63 +1042,154 @@ shadow-rounded-2 index: -1 bridge-conduit-arrow rotate: false - xy: 323, 15 + xy: 323, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conduit-bridge rotate: false - xy: 333, 25 + xy: 333, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conduit-end rotate: false - xy: 323, 5 + xy: 343, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 conduit-bottom rotate: false - xy: 363, 15 + xy: 363, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 -conduit-top +conduit-bottom-0 rotate: false - xy: 363, 5 + xy: 373, 15 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-1 + rotate: false + xy: 383, 25 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-2 + rotate: false + xy: 373, 5 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-3 + rotate: false + xy: 383, 15 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-4 + rotate: false + xy: 393, 25 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-5 + rotate: false + xy: 383, 5 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-bottom-6 + rotate: false + xy: 393, 15 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-0 + rotate: false + xy: 403, 25 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-1 + rotate: false + xy: 403, 15 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-2 + rotate: false + xy: 403, 5 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-3 + rotate: false + xy: 517, 131 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-4 + rotate: false + xy: 517, 121 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-5 + rotate: false + xy: 517, 111 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +conduit-top-6 + rotate: false + xy: 517, 101 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-router rotate: false - xy: 557, 181 + xy: 522, 151 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-router-bottom rotate: false - xy: 545, 171 + xy: 520, 141 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-router-liquid rotate: false - xy: 567, 181 + xy: 532, 151 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-router-top rotate: false - xy: 555, 171 + xy: 530, 141 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1119,35 +1217,70 @@ liquid-tank-top index: -1 phase-conduit-arrow rotate: false - xy: 587, 128 + xy: 617, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conduit-bridge rotate: false - xy: 577, 108 + xy: 627, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conduit-end rotate: false - xy: 587, 118 + xy: 617, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 -pulse-conduit-bottom +pulse-conduit-top-0 rotate: false - xy: 607, 118 + xy: 637, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 -pulse-conduit-top +pulse-conduit-top-1 rotate: false - xy: 617, 128 + xy: 647, 118 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +pulse-conduit-top-2 + rotate: false + xy: 647, 108 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +pulse-conduit-top-3 + rotate: false + xy: 567, 98 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +pulse-conduit-top-4 + rotate: false + xy: 577, 98 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +pulse-conduit-top-5 + rotate: false + xy: 587, 98 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +pulse-conduit-top-6 + rotate: false + xy: 597, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1252,7 +1385,7 @@ nuclear-reactor-lights index: -1 rtg-generator-top rotate: false - xy: 627, 118 + xy: 662, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1427,7 +1560,14 @@ cultivator-top index: -1 lavasmelter rotate: false - xy: 507, 181 + xy: 545, 171 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +oilrefinery + rotate: false + xy: 552, 151 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1469,21 +1609,21 @@ poweralloysmelter-top index: -1 pulverizer rotate: false - xy: 607, 108 + xy: 607, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 pulverizer-rotator rotate: false - xy: 617, 118 + xy: 617, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 separator-liquid rotate: false - xy: 647, 108 + xy: 672, 159 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1497,14 +1637,14 @@ core-open index: -1 block-1 rotate: false - xy: 512, 73 + xy: 957, 349 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-1-top rotate: false - xy: 957, 359 + xy: 921, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1581,7 +1721,7 @@ mass-driver-turret index: -1 duo rotate: false - xy: 393, 25 + xy: 977, 346 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1686,14 +1826,14 @@ salvo-panel-right index: -1 scorch rotate: false - xy: 500, 69 + xy: 428, 56 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 scorch-shoot rotate: false - xy: 416, 58 + xy: 440, 56 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -1784,7 +1924,7 @@ reconstructor-open index: -1 repair-point-turret rotate: false - xy: 627, 128 + xy: 627, 98 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1805,7 +1945,7 @@ door-large-open index: -1 door-open rotate: false - xy: 383, 15 + xy: 967, 346 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1917,7 +2057,7 @@ missile index: -1 missile-back rotate: false - xy: 452, 57 + xy: 476, 57 size: 9, 9 orig: 9, 9 offset: 0, 0 @@ -1959,21 +2099,21 @@ scorch5 index: -1 shell rotate: false - xy: 463, 57 + xy: 487, 57 size: 9, 9 orig: 9, 9 offset: 0, 0 index: -1 shell-back rotate: false - xy: 474, 57 + xy: 974, 366 size: 9, 9 orig: 9, 9 offset: 0, 0 index: -1 shot rotate: false - xy: 567, 98 + xy: 682, 159 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -1987,7 +2127,7 @@ transfer index: -1 transfer-arrow rotate: false - xy: 667, 128 + xy: 741, 201 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2022,49 +2162,49 @@ block-icon-blast-drill index: -1 block-icon-bridge-conduit rotate: false - xy: 931, 335 + xy: 951, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conduit rotate: false - xy: 931, 335 + xy: 951, 335 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-bridge-conveyor rotate: false - xy: 941, 335 + xy: 728, 291 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 bridge-conveyor rotate: false - xy: 941, 335 + xy: 728, 291 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-carbide-drill rotate: false - xy: 951, 335 + xy: 728, 281 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-carbide-wall rotate: false - xy: 496, 58 + xy: 728, 271 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 carbide-wall rotate: false - xy: 496, 58 + xy: 728, 271 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2099,35 +2239,35 @@ centrifuge index: -1 block-icon-combustion-generator rotate: false - xy: 506, 59 + xy: 728, 261 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 combustion-generator rotate: false - xy: 506, 59 + xy: 728, 261 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-conduit rotate: false - xy: 728, 291 + xy: 728, 251 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-conveyor rotate: false - xy: 728, 281 + xy: 726, 241 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 conveyor rotate: false - xy: 728, 281 + xy: 726, 241 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2183,42 +2323,42 @@ dart-ship-factory index: -1 block-icon-deepwater rotate: false - xy: 728, 271 + xy: 726, 231 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 deepwater rotate: false - xy: 728, 271 + xy: 726, 231 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-deflector-wall rotate: false - xy: 728, 261 + xy: 726, 221 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 deflector-wall rotate: false - xy: 728, 261 + xy: 726, 221 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-wall rotate: false - xy: 728, 261 + xy: 726, 221 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-phase-wall rotate: false - xy: 728, 261 + xy: 726, 221 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2267,63 +2407,77 @@ delta-mech-factory index: -1 block-icon-dirt rotate: false - xy: 728, 251 + xy: 726, 211 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 dirt1 rotate: false - xy: 728, 251 + xy: 726, 211 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 +block-icon-distributor + rotate: false + xy: 597, 188 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +distributor + rotate: false + xy: 597, 188 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 block-icon-door rotate: false - xy: 726, 241 + xy: 863, 309 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 door rotate: false - xy: 726, 241 + xy: 863, 309 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-door-large rotate: false - xy: 597, 188 + xy: 615, 188 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 door-large rotate: false - xy: 597, 188 + xy: 615, 188 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-icon-drone-factory rotate: false - xy: 615, 188 + xy: 633, 188 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-icon-drop-point rotate: false - xy: 726, 231 + xy: 861, 299 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 drop-point rotate: false - xy: 726, 231 + xy: 861, 299 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2337,7 +2491,7 @@ block-icon-duo index: -1 block-icon-fabricator-factory rotate: false - xy: 633, 188 + xy: 665, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -2358,14 +2512,14 @@ block-icon-fusion-reactor index: -1 block-icon-grass rotate: false - xy: 726, 221 + xy: 289, 53 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 grass1 rotate: false - xy: 726, 221 + xy: 289, 53 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2379,98 +2533,98 @@ block-icon-hail index: -1 block-icon-ice rotate: false - xy: 726, 211 + xy: 289, 43 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ice1 rotate: false - xy: 726, 211 + xy: 289, 43 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-icerock rotate: false - xy: 863, 309 + xy: 289, 33 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 icerock1 rotate: false - xy: 863, 309 + xy: 289, 33 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-incinerator rotate: false - xy: 861, 299 + xy: 299, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 incinerator rotate: false - xy: 861, 299 + xy: 299, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-itemsource rotate: false - xy: 289, 53 + xy: 309, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 itemsource rotate: false - xy: 289, 53 + xy: 309, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-itemvoid rotate: false - xy: 289, 43 + xy: 299, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 itemvoid rotate: false - xy: 289, 43 + xy: 299, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-javelin-ship-factory rotate: false - xy: 665, 187 + xy: 683, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 javelin-ship-factory rotate: false - xy: 665, 187 + xy: 683, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-icon-junction rotate: false - xy: 289, 33 + xy: 319, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 junction rotate: false - xy: 289, 33 + xy: 319, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2484,42 +2638,42 @@ block-icon-lancer index: -1 block-icon-laser-drill rotate: false - xy: 683, 187 + xy: 456, 140 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-icon-lava rotate: false - xy: 299, 55 + xy: 299, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 lava rotate: false - xy: 299, 55 + xy: 299, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-liquid-junction rotate: false - xy: 309, 55 + xy: 309, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-junction rotate: false - xy: 309, 55 + xy: 309, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-liquid-router rotate: false - xy: 299, 45 + xy: 329, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2533,14 +2687,14 @@ block-icon-liquid-tank index: -1 block-icon-liquidsource rotate: false - xy: 319, 55 + xy: 309, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquidsource rotate: false - xy: 319, 55 + xy: 309, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2568,14 +2722,14 @@ core-top index: -1 block-icon-mechanical-pump rotate: false - xy: 299, 35 + xy: 319, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 mechanical-pump rotate: false - xy: 299, 35 + xy: 319, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2589,46 +2743,32 @@ block-icon-meltdown index: -1 block-icon-melter rotate: false - xy: 309, 45 + xy: 339, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 melter rotate: false - xy: 309, 45 + xy: 339, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-metalfloor rotate: false - xy: 329, 55 + xy: 319, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 metalfloor1 rotate: false - xy: 329, 55 + xy: 319, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 -block-icon-multiplexer - rotate: false - xy: 456, 140 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -multiplexer - rotate: false - xy: 456, 140 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 block-icon-nuclear-reactor rotate: false xy: 203, 135 @@ -2645,14 +2785,14 @@ nuclear-reactor index: -1 block-icon-oil rotate: false - xy: 309, 35 + xy: 329, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 oil rotate: false - xy: 309, 35 + xy: 329, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2664,58 +2804,44 @@ block-icon-oil-extractor orig: 24, 24 offset: 0, 0 index: -1 -block-icon-oilrefinery - rotate: false - xy: 319, 45 - size: 8, 8 - orig: 8, 8 - offset: 0, 0 - index: -1 -oilrefinery - rotate: false - xy: 319, 45 - size: 8, 8 - orig: 8, 8 - offset: 0, 0 - index: -1 block-icon-overflow-gate rotate: false - xy: 339, 55 + xy: 349, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 overflow-gate rotate: false - xy: 339, 55 + xy: 349, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-phase-conduit rotate: false - xy: 319, 35 + xy: 329, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conduit rotate: false - xy: 319, 35 + xy: 329, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-phase-conveyor rotate: false - xy: 329, 45 + xy: 339, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 phase-conveyor rotate: false - xy: 329, 45 + xy: 339, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2750,14 +2876,14 @@ plastanium-compressor index: -1 block-icon-power-node rotate: false - xy: 349, 55 + xy: 359, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 power-node rotate: false - xy: 349, 55 + xy: 359, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2778,42 +2904,42 @@ power-node-large index: -1 block-icon-powerinfinite rotate: false - xy: 329, 35 + xy: 339, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 powerinfinite rotate: false - xy: 329, 35 + xy: 339, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-powervoid rotate: false - xy: 339, 45 + xy: 349, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 powervoid rotate: false - xy: 339, 45 + xy: 349, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-pulse-conduit rotate: false - xy: 359, 55 + xy: 369, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-pulverizer rotate: false - xy: 339, 35 + xy: 349, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2862,28 +2988,28 @@ reconstructor index: -1 block-icon-repair-point rotate: false - xy: 349, 45 + xy: 359, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 repair-point rotate: false - xy: 349, 45 + xy: 359, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-resupply-point rotate: false - xy: 369, 55 + xy: 379, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 resupply-point rotate: false - xy: 369, 55 + xy: 379, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2897,14 +3023,14 @@ block-icon-ripple index: -1 block-icon-rock rotate: false - xy: 349, 35 + xy: 359, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 rock1 rotate: false - xy: 349, 35 + xy: 359, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2923,30 +3049,16 @@ rotary-pump orig: 16, 16 offset: 0, 0 index: -1 -block-icon-router - rotate: false - xy: 359, 45 - size: 8, 8 - orig: 8, 8 - offset: 0, 0 - index: -1 -router - rotate: false - xy: 359, 45 - size: 8, 8 - orig: 8, 8 - offset: 0, 0 - index: -1 block-icon-rtg-generator rotate: false - xy: 379, 55 + xy: 369, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 rtg-generator rotate: false - xy: 379, 55 + xy: 369, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2960,14 +3072,14 @@ block-icon-salvo index: -1 block-icon-sand rotate: false - xy: 359, 35 + xy: 389, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sand1 rotate: false - xy: 359, 35 + xy: 389, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -2981,28 +3093,28 @@ block-icon-scorch index: -1 block-icon-separator rotate: false - xy: 369, 45 + xy: 369, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 separator rotate: false - xy: 369, 45 + xy: 369, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-shrub rotate: false - xy: 389, 55 + xy: 379, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 shrub rotate: false - xy: 389, 55 + xy: 379, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3023,42 +3135,42 @@ silicon-smelter index: -1 block-icon-smelter rotate: false - xy: 369, 35 + xy: 379, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 smelter rotate: false - xy: 369, 35 + xy: 379, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-snow rotate: false - xy: 379, 45 + xy: 389, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 snow1 rotate: false - xy: 379, 45 + xy: 389, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-solar-panel rotate: false - xy: 379, 35 + xy: 389, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 solar-panel rotate: false - xy: 379, 35 + xy: 389, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3079,56 +3191,56 @@ solar-panel-large index: -1 block-icon-solidifer rotate: false - xy: 389, 45 + xy: 399, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 solidifer rotate: false - xy: 389, 45 + xy: 399, 55 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-sortedunloader rotate: false - xy: 389, 35 + xy: 399, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sortedunloader rotate: false - xy: 389, 35 + xy: 399, 45 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-sorter rotate: false - xy: 399, 55 + xy: 399, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 sorter rotate: false - xy: 399, 55 + xy: 399, 35 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-space rotate: false - xy: 399, 45 + xy: 293, 23 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 space rotate: false - xy: 399, 45 + xy: 293, 23 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3142,28 +3254,28 @@ block-icon-spectre index: -1 block-icon-splitter rotate: false - xy: 399, 35 + xy: 293, 13 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 splitter rotate: false - xy: 399, 35 + xy: 293, 13 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-stone rotate: false - xy: 293, 23 + xy: 293, 3 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 stone1 rotate: false - xy: 293, 23 + xy: 293, 3 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3205,14 +3317,14 @@ thermal-pump index: -1 block-icon-thorium-wall rotate: false - xy: 293, 13 + xy: 303, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 thorium-wall rotate: false - xy: 293, 13 + xy: 303, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3233,35 +3345,35 @@ thorium-wall-large index: -1 block-icon-titanium-conveyor rotate: false - xy: 293, 3 + xy: 303, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 titanium-conveyor rotate: false - xy: 293, 3 + xy: 303, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-tungsten-drill rotate: false - xy: 303, 25 + xy: 313, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 block-icon-tungsten-wall rotate: false - xy: 303, 15 + xy: 303, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 tungsten-wall rotate: false - xy: 303, 15 + xy: 303, 5 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3296,14 +3408,14 @@ turbine-generator index: -1 block-icon-unloader rotate: false - xy: 313, 25 + xy: 313, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 unloader rotate: false - xy: 313, 25 + xy: 313, 15 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3338,14 +3450,14 @@ warp-gate index: -1 block-icon-water rotate: false - xy: 303, 5 + xy: 323, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 water rotate: false - xy: 303, 5 + xy: 323, 25 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3366,28 +3478,28 @@ block-icon-wave index: -1 liquid-icon-cryofluid rotate: false - xy: 537, 181 + xy: 532, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-icon-lava rotate: false - xy: 525, 171 + xy: 542, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-icon-oil rotate: false - xy: 547, 181 + xy: 552, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-icon-water rotate: false - xy: 535, 171 + xy: 562, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3443,525 +3555,525 @@ mech-icon-tau-mech index: -1 ore-coal-grass1 rotate: false - xy: 562, 161 + xy: 550, 141 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-grass2 rotate: false - xy: 522, 151 + xy: 527, 111 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-grass3 rotate: false - xy: 520, 141 + xy: 537, 121 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-ice1 rotate: false - xy: 532, 151 + xy: 547, 131 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-ice2 rotate: false - xy: 530, 141 + xy: 562, 151 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-ice3 rotate: false - xy: 527, 131 + xy: 560, 141 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-sand1 rotate: false - xy: 542, 151 + xy: 527, 101 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-sand2 rotate: false - xy: 540, 141 + xy: 537, 111 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-sand3 rotate: false - xy: 527, 121 + xy: 547, 121 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-snow1 rotate: false - xy: 537, 131 + xy: 557, 131 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-snow2 rotate: false - xy: 552, 151 + xy: 537, 101 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-snow3 rotate: false - xy: 550, 141 + xy: 547, 111 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-stone1 rotate: false - xy: 527, 111 + xy: 557, 121 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-stone2 rotate: false - xy: 537, 121 + xy: 547, 101 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-coal-stone3 rotate: false - xy: 547, 131 + xy: 557, 111 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-grass1 rotate: false - xy: 562, 151 + xy: 557, 101 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-grass2 rotate: false - xy: 560, 141 + xy: 577, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-grass3 rotate: false - xy: 527, 101 + xy: 587, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-ice1 rotate: false - xy: 537, 111 + xy: 597, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-ice2 rotate: false - xy: 547, 121 + xy: 607, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-ice3 rotate: false - xy: 557, 131 + xy: 617, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-sand1 rotate: false - xy: 537, 101 + xy: 627, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-sand2 rotate: false - xy: 547, 111 + xy: 637, 178 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-sand3 rotate: false - xy: 557, 121 + xy: 575, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-snow1 rotate: false - xy: 547, 101 + xy: 585, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-snow2 rotate: false - xy: 557, 111 + xy: 595, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-snow3 rotate: false - xy: 557, 101 + xy: 605, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-stone1 rotate: false - xy: 577, 178 + xy: 615, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-stone2 rotate: false - xy: 587, 178 + xy: 625, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-lead-stone3 rotate: false - xy: 597, 178 + xy: 635, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-grass1 rotate: false - xy: 607, 178 + xy: 572, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-grass2 rotate: false - xy: 617, 178 + xy: 582, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-grass3 rotate: false - xy: 627, 178 + xy: 592, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-ice1 rotate: false - xy: 637, 178 + xy: 602, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-ice2 rotate: false - xy: 575, 168 + xy: 612, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-ice3 rotate: false - xy: 585, 168 + xy: 622, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-sand1 rotate: false - xy: 595, 168 + xy: 632, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-sand2 rotate: false - xy: 605, 168 + xy: 572, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-sand3 rotate: false - xy: 615, 168 + xy: 582, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-snow1 rotate: false - xy: 625, 168 + xy: 592, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-snow2 rotate: false - xy: 635, 168 + xy: 602, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-snow3 rotate: false - xy: 572, 158 + xy: 612, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-stone1 rotate: false - xy: 582, 158 + xy: 622, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-stone2 rotate: false - xy: 592, 158 + xy: 632, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-thorium-stone3 rotate: false - xy: 602, 158 + xy: 645, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-grass1 rotate: false - xy: 612, 158 + xy: 655, 168 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-grass2 rotate: false - xy: 622, 158 + xy: 642, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-grass3 rotate: false - xy: 632, 158 + xy: 642, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-ice1 rotate: false - xy: 572, 148 + xy: 652, 158 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-ice2 rotate: false - xy: 582, 148 + xy: 652, 148 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-ice3 rotate: false - xy: 592, 148 + xy: 570, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-sand1 rotate: false - xy: 602, 148 + xy: 580, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-sand2 rotate: false - xy: 612, 148 + xy: 590, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-sand3 rotate: false - xy: 622, 148 + xy: 600, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-snow1 rotate: false - xy: 632, 148 + xy: 610, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-snow2 rotate: false - xy: 645, 168 + xy: 620, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-snow3 rotate: false - xy: 655, 168 + xy: 630, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-stone1 rotate: false - xy: 642, 158 + xy: 640, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-stone2 rotate: false - xy: 642, 148 + xy: 650, 138 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-titanium-stone3 rotate: false - xy: 652, 158 + xy: 567, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-grass1 rotate: false - xy: 652, 148 + xy: 567, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-grass2 rotate: false - xy: 570, 138 + xy: 577, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-grass3 rotate: false - xy: 580, 138 + xy: 567, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-ice1 rotate: false - xy: 590, 138 + xy: 577, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-ice2 rotate: false - xy: 600, 138 + xy: 587, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-ice3 rotate: false - xy: 610, 138 + xy: 577, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-sand1 rotate: false - xy: 620, 138 + xy: 587, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-sand2 rotate: false - xy: 630, 138 + xy: 597, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-sand3 rotate: false - xy: 640, 138 + xy: 587, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-snow1 rotate: false - xy: 650, 138 + xy: 597, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-snow2 rotate: false - xy: 567, 128 + xy: 607, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-snow3 rotate: false - xy: 567, 118 + xy: 597, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-stone1 rotate: false - xy: 577, 128 + xy: 607, 118 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-stone2 rotate: false - xy: 567, 108 + xy: 617, 128 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 ore-tungsten-stone3 rotate: false - xy: 577, 118 + xy: 607, 108 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -3996,119 +4108,112 @@ vtol index: -1 item-biomatter rotate: false - xy: 997, 345 + xy: 721, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-blast-compound rotate: false - xy: 1007, 349 + xy: 731, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-carbide rotate: false - xy: 1007, 339 + xy: 775, 302 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-coal rotate: false - xy: 409, 48 + xy: 785, 302 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-lead rotate: false - xy: 409, 38 + xy: 795, 302 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-phase-matter rotate: false - xy: 413, 28 + xy: 507, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-plastanium rotate: false - xy: 413, 18 + xy: 505, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-pyratite rotate: false - xy: 413, 8 + xy: 517, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-sand rotate: false - xy: 701, 161 + xy: 527, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-silicon rotate: false - xy: 711, 161 + xy: 515, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-stone rotate: false - xy: 721, 161 + xy: 537, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-surge-alloy rotate: false - xy: 731, 161 + xy: 525, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-thorium rotate: false - xy: 775, 302 + xy: 547, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-titanium rotate: false - xy: 785, 302 + xy: 535, 171 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 item-tungsten rotate: false - xy: 795, 302 + xy: 557, 181 size: 8, 8 orig: 8, 8 offset: 0, 0 index: -1 liquid-icon rotate: false - xy: 515, 171 - size: 8, 8 - orig: 8, 8 - offset: 0, 0 - index: -1 -liquid-icon-none - rotate: false - xy: 515, 171 + xy: 522, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -4759,9 +4864,16 @@ icon-itch.io orig: 14, 14 offset: 0, 0 index: -1 +icon-item + rotate: false + xy: 404, 66 + size: 10, 10 + orig: 10, 10 + offset: 0, 0 + index: -1 icon-items-none rotate: false - xy: 987, 345 + xy: 711, 161 size: 8, 8 orig: 8, 8 offset: 0, 0 @@ -4782,7 +4894,7 @@ icon-link index: -1 icon-liquid rotate: false - xy: 404, 66 + xy: 416, 70 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -4824,7 +4936,7 @@ icon-locked index: -1 icon-logic rotate: false - xy: 416, 70 + xy: 428, 80 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -4838,7 +4950,7 @@ icon-map index: -1 icon-menu rotate: false - xy: 428, 80 + xy: 440, 80 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -4850,16 +4962,23 @@ icon-menu-large orig: 16, 16 offset: 0, 0 index: -1 +icon-missing + rotate: false + xy: 452, 80 + size: 10, 10 + orig: 10, 10 + offset: 0, 0 + index: -1 icon-none rotate: false - xy: 440, 80 + xy: 464, 80 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 icon-pause rotate: false - xy: 452, 80 + xy: 476, 80 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -4887,7 +5006,7 @@ icon-pick index: -1 icon-play rotate: false - xy: 464, 80 + xy: 488, 80 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -4901,21 +5020,21 @@ icon-play-2 index: -1 icon-players rotate: false - xy: 476, 80 + xy: 500, 81 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 icon-power rotate: false - xy: 488, 80 + xy: 428, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 icon-production rotate: false - xy: 500, 81 + xy: 440, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -5006,7 +5125,7 @@ icon-save-map index: -1 icon-settings rotate: false - xy: 428, 68 + xy: 452, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -5027,14 +5146,14 @@ icon-tools index: -1 icon-touch rotate: false - xy: 440, 68 + xy: 464, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 icon-touchDelete rotate: false - xy: 452, 68 + xy: 476, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -5076,7 +5195,7 @@ icon-undo index: -1 icon-units rotate: false - xy: 464, 68 + xy: 488, 68 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -5090,7 +5209,7 @@ icon-unlocks index: -1 icon-weapon rotate: false - xy: 476, 68 + xy: 500, 69 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -5369,7 +5488,7 @@ titan-leg index: -1 vtol-flame rotate: false - xy: 485, 57 + xy: 512, 82 size: 9, 9 orig: 9, 9 offset: 0, 0 diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 3900661c1d..367ec17fe6 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/src/Mindustry.gwt.xml b/core/src/Mindustry.gwt.xml index c7a38eeb99..95e2e371aa 100644 --- a/core/src/Mindustry.gwt.xml +++ b/core/src/Mindustry.gwt.xml @@ -1,24 +1,22 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/Mindustry.java b/core/src/io/anuke/mindustry/Mindustry.java index 79c208d4cb..804baca4e4 100644 --- a/core/src/io/anuke/mindustry/Mindustry.java +++ b/core/src/io/anuke/mindustry/Mindustry.java @@ -1,6 +1,5 @@ package io.anuke.mindustry; -import com.badlogic.gdx.utils.async.AsyncExecutor; import io.anuke.mindustry.core.*; import io.anuke.mindustry.io.BundleLoader; import io.anuke.ucore.core.Timers; @@ -9,36 +8,35 @@ import io.anuke.ucore.util.Log; import static io.anuke.mindustry.Vars.*; -public class Mindustry extends ModuleCore { - private AsyncExecutor exec = new AsyncExecutor(1); +public class Mindustry extends ModuleCore{ - @Override - public void init(){ - Timers.mark(); + @Override + public void init(){ + Timers.mark(); - Vars.init(); + Vars.init(); - debug = Platform.instance.isDebug(); + debug = Platform.instance.isDebug(); - Log.setUseColors(false); - BundleLoader.load(); - ContentLoader.load(); + Log.setUseColors(false); + BundleLoader.load(); + ContentLoader.load(); - module(logic = new Logic()); - module(world = new World()); - module(control = new Control()); - module(renderer = new Renderer()); - module(ui = new UI()); - module(netServer = new NetServer()); - module(netClient = new NetClient()); + module(logic = new Logic()); + module(world = new World()); + module(control = new Control()); + module(renderer = new Renderer()); + module(ui = new UI()); + module(netServer = new NetServer()); + module(netClient = new NetClient()); Log.info("Time to load [total]: {0}", Timers.elapsed()); - } + } - @Override - public void render(){ - super.render(); - threads.handleRender(); - } + @Override + public void render(){ + super.render(); + threads.handleRender(); + } } diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index b834594eed..193e97a9ba 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -19,8 +19,8 @@ import io.anuke.mindustry.io.Version; import io.anuke.mindustry.net.Net; import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.EntityGroup; -import io.anuke.ucore.entities.trait.DrawTrait; import io.anuke.ucore.entities.impl.EffectEntity; +import io.anuke.ucore.entities.trait.DrawTrait; import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.util.OS; import io.anuke.ucore.util.Translator; @@ -28,167 +28,150 @@ import io.anuke.ucore.util.Translator; import java.util.Locale; public class Vars{ - public static boolean testMobile; - //shorthand for whether or not this is running on android or ios - public static boolean mobile; - public static boolean ios; - public static boolean android; - //shorthand for whether or not this is running on GWT - public static boolean gwt; - - //respawn time in frames - public static final float respawnduration = 60*4; - //time between waves in frames (on normal mode) - public static final float wavespace = 60*60*2f; - //waves can last no longer than 3 minutes, otherwise the next one spawns - public static final float maxwavespace = 60*60*4f; - - //set ridiculously high for now - public static final float coreBuildRange = 800999f; - //discord group URL - public static final String discordURL = "https://discord.gg/BKADYds"; - - public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases"; - - //directory for user-created map data - public static FileHandle customMapDirectory; - //save file directory - public static FileHandle saveDirectory; - public static String mapExtension = "mmap"; - public static String saveExtension = "msav"; - //scale of the font - public static float fontScale; - //camera zoom displayed on startup - public static int baseCameraScale; - //if true, player speed will be increased, massive amounts of resources will be given on start, and other debug options will be available - public static boolean debug = false; - public static boolean console = false; - //whether the player can clip through walls - public static boolean noclip = false; - //whether turrets have infinite ammo (only with debug) - public static boolean infiniteAmmo = true; - //whether to show paths of enemies - public static boolean showPaths = false; - //if false, player is always hidden - public static boolean showPlayer = true; - //whether to hide ui, only on debug - public static boolean showUI = true; - //whether to show block debug - public static boolean showBlockDebug = false; - - public static boolean showFog = true; - + //respawn time in frames + public static final float respawnduration = 60 * 4; + //time between waves in frames (on normal mode) + public static final float wavespace = 60 * 60 * 2f; + //waves can last no longer than 3 minutes, otherwise the next one spawns + public static final float maxwavespace = 60 * 60 * 4f; + //set ridiculously high for now + public static final float coreBuildRange = 800999f; + //discord group URL + public static final String discordURL = "https://discord.gg/BKADYds"; + public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases"; public static final int maxTextLength = 150; public static final int maxNameLength = 40; public static final int maxCharNameLength = 20; + public static final int saveSlots = 64; + public static final float itemSize = 5f; + public static final int tilesize = 8; + public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"), + new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")}; + public static final Color[] playerColors = { + Color.valueOf("82759a"), + Color.valueOf("c0c1c5"), + Color.valueOf("fff0e7"), + Color.valueOf("7d2953"), + Color.valueOf("ff074e"), + Color.valueOf("ff072a"), + Color.valueOf("ff76a6"), + Color.valueOf("a95238"), + Color.valueOf("ffa108"), + Color.valueOf("feeb2c"), + Color.valueOf("ffcaa8"), + Color.valueOf("008551"), + Color.valueOf("00e339"), + Color.valueOf("423c7b"), + Color.valueOf("4b5ef1"), + Color.valueOf("2cabfe"), + }; + //server port + public static final int port = 6567; + public static final int webPort = 6568; + public static boolean testMobile; + //shorthand for whether or not this is running on android or ios + public static boolean mobile; + public static boolean ios; + public static boolean android; + //shorthand for whether or not this is running on GWT + public static boolean gwt; + //directory for user-created map data + public static FileHandle customMapDirectory; + //save file directory + public static FileHandle saveDirectory; + public static String mapExtension = "mmap"; + public static String saveExtension = "msav"; + //scale of the font + public static float fontScale; + //camera zoom displayed on startup + public static int baseCameraScale; + //if true, player speed will be increased, massive amounts of resources will be given on start, and other debug options will be available + public static boolean debug = false; + public static boolean console = false; + //whether the player can clip through walls + public static boolean noclip = false; + //whether turrets have infinite ammo (only with debug) + public static boolean infiniteAmmo = true; + //whether to show paths of enemies + public static boolean showPaths = false; + //if false, player is always hidden + public static boolean showPlayer = true; + //whether to hide ui, only on debug + public static boolean showUI = true; + //whether to show block debug + public static boolean showBlockDebug = false; + public static boolean showFog = true; + public static boolean headless = false; + public static float controllerMin = 0.25f; + public static float baseControllerSpeed = 11f; + //only if smoothCamera + public static boolean snapCamera = true; + public static GameState state; + public static ThreadHandler threads; - public static boolean headless = false; + public static Control control; + public static Logic logic; + public static Renderer renderer; + public static UI ui; + public static World world; + public static NetServer netServer; + public static NetClient netClient; - public static float controllerMin = 0.25f; + public static Player[] players = {}; - public static float baseControllerSpeed = 11f; + public static EntityGroup playerGroup; + public static EntityGroup tileGroup; + public static EntityGroup bulletGroup; + public static EntityGroup shieldGroup; + public static EntityGroup effectGroup; + public static EntityGroup groundEffectGroup; + public static EntityGroup itemGroup; - public static final int saveSlots = 64; + public static EntityGroup puddleGroup; + public static EntityGroup fireGroup; + public static EntityGroup[] unitGroups; - public static final float itemSize = 5f; + public static final Translator[] tmptr = new Translator[]{new Translator(), new Translator(), new Translator(), new Translator()}; - //only if smoothCamera - public static boolean snapCamera = true; - - public static final int tilesize = 8; + public static void init(){ + Version.init(); - public static final Translator[] tmptr = new Translator[]{new Translator(), new Translator(), new Translator(), new Translator()}; + playerGroup = Entities.addGroup(Player.class).enableMapping(); + tileGroup = Entities.addGroup(TileEntity.class, false); + bulletGroup = Entities.addGroup(Bullet.class).enableMapping(); + shieldGroup = Entities.addGroup(Shield.class, false); + effectGroup = Entities.addGroup(EffectEntity.class, false); + groundEffectGroup = Entities.addGroup(DrawTrait.class, false); + puddleGroup = Entities.addGroup(Puddle.class, false).enableMapping(); + itemGroup = Entities.addGroup(ItemDrop.class).enableMapping(); + fireGroup = Entities.addGroup(Fire.class, false).enableMapping(); + unitGroups = new EntityGroup[Team.all.length]; - public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"), - new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")}; + for(Team team : Team.all){ + unitGroups[team.ordinal()] = Entities.addGroup(BaseUnit.class).enableMapping(); + } - public static final Color[] playerColors = { - Color.valueOf("82759a"), - Color.valueOf("c0c1c5"), - Color.valueOf("fff0e7"), - Color.valueOf("7d2953"), - Color.valueOf("ff074e"), - Color.valueOf("ff072a"), - Color.valueOf("ff76a6"), - Color.valueOf("a95238"), - Color.valueOf("ffa108"), - Color.valueOf("feeb2c"), - Color.valueOf("ffcaa8"), - Color.valueOf("008551"), - Color.valueOf("00e339"), - Color.valueOf("423c7b"), - Color.valueOf("4b5ef1"), - Color.valueOf("2cabfe"), - }; + for(EntityGroup group : Entities.getAllGroups()){ + group.setRemoveListener(entity -> { + if(entity instanceof SyncTrait && Net.client()){ + netClient.addRemovedEntity((entity).getID()); + } + }); + } - //server port - public static final int port = 6567; - public static final int webPort = 6568; + threads = new ThreadHandler(Platform.instance.getThreadProvider()); - public static GameState state; - public static ThreadHandler threads; + mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile; + ios = Gdx.app.getType() == ApplicationType.iOS; + android = Gdx.app.getType() == ApplicationType.Android; + gwt = Gdx.app.getType() == ApplicationType.WebGL; - public static Control control; - public static Logic logic; - public static Renderer renderer; - public static UI ui; - public static World world; - public static NetServer netServer; - public static NetClient netClient; - - public static Player[] players = {}; + if(!gwt){ + customMapDirectory = OS.getAppDataDirectory("Mindustry").child("maps/"); + saveDirectory = OS.getAppDataDirectory("Mindustry").child("saves/"); + } - public static EntityGroup playerGroup; - public static EntityGroup tileGroup; - public static EntityGroup bulletGroup; - public static EntityGroup shieldGroup; - public static EntityGroup effectGroup; - public static EntityGroup groundEffectGroup; - public static EntityGroup itemGroup; - - public static EntityGroup puddleGroup; - public static EntityGroup fireGroup; - public static EntityGroup[] unitGroups; - - public static void init(){ - Version.init(); - - playerGroup = Entities.addGroup(Player.class).enableMapping(); - tileGroup = Entities.addGroup(TileEntity.class, false); - bulletGroup = Entities.addGroup(Bullet.class).enableMapping(); - shieldGroup = Entities.addGroup(Shield.class, false); - effectGroup = Entities.addGroup(EffectEntity.class, false); - groundEffectGroup = Entities.addGroup(DrawTrait.class, false); - puddleGroup = Entities.addGroup(Puddle.class, false).enableMapping(); - itemGroup = Entities.addGroup(ItemDrop.class).enableMapping(); - fireGroup = Entities.addGroup(Fire.class, false).enableMapping(); - unitGroups = new EntityGroup[Team.all.length]; - - for(Team team : Team.all){ - unitGroups[team.ordinal()] = Entities.addGroup(BaseUnit.class).enableMapping(); - } - - for(EntityGroup group : Entities.getAllGroups()){ - group.setRemoveListener(entity -> { - if(entity instanceof SyncTrait && Net.client()){ - netClient.addRemovedEntity(((SyncTrait) entity).getID()); - } - }); - } - - threads = new ThreadHandler(Platform.instance.getThreadProvider()); - - mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile; - ios = Gdx.app.getType() == ApplicationType.iOS; - android = Gdx.app.getType() == ApplicationType.Android; - gwt = Gdx.app.getType() == ApplicationType.WebGL; - - if(!gwt) { - customMapDirectory = OS.getAppDataDirectory("Mindustry").child("maps/"); - saveDirectory = OS.getAppDataDirectory("Mindustry").child("saves/"); - } - - fontScale = Math.max(Unit.dp.scl(1f)/2f, 0.5f); - baseCameraScale = Math.round(Unit.dp.scl(4)); - } + fontScale = Math.max(Unit.dp.scl(1f) / 2f, 0.5f); + baseCameraScale = Math.round(Unit.dp.scl(4)); + } } diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index 38a3f8309f..ae21cd4e13 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -26,32 +26,53 @@ import static io.anuke.mindustry.Vars.*; //TODO consider using quadtrees for finding specific types of blocks within an area //TODO maybe use Arrays instead of ObjectSets? -/**Class used for indexing special target blocks for AI.*/ -public class BlockIndexer { - /**Size of one ore quadrant.*/ + +/** + * Class used for indexing special target blocks for AI. + */ +public class BlockIndexer{ + /** + * Size of one ore quadrant. + */ private final static int oreQuadrantSize = 20; - /**Size of one structure quadrant.*/ + /** + * Size of one structure quadrant. + */ private final static int structQuadrantSize = 12; - /**Set of all ores that are being scanned.*/ + /** + * Set of all ores that are being scanned. + */ private final ObjectSet scanOres = ObjectSet.with(Items.tungsten, Items.coal, Items.lead, Items.thorium, Items.titanium); - /**Stores all ore quadtrants on the map.*/ - private ObjectMap> ores; - private final ObjectSet itemSet = new ObjectSet<>(); - - /**Tags all quadrants.*/ + /** + * Stores all ore quadtrants on the map. + */ + private ObjectMap> ores; + /** + * Tags all quadrants. + */ private Bits[] structQuadrants; - /**Maps teams to a map of flagged tiles by type.*/ + /** + * Maps teams to a map of flagged tiles by type. + */ private ObjectMap> enemyMap = new ObjectMap<>(); - /**Maps teams to a map of flagged tiles by type.*/ + /** + * Maps teams to a map of flagged tiles by type. + */ private ObjectMap> allyMap = new ObjectMap<>(); - /**Empty map for invalid teams.*/ + /** + * Empty map for invalid teams. + */ private ObjectMap> emptyMap = new ObjectMap<>(); - /**Maps tile positions to their last known tile index data.*/ + /** + * Maps tile positions to their last known tile index data. + */ private IntMap typeMap = new IntMap<>(); - /**Empty array used for returning.*/ + /** + * Empty array used for returning. + */ private ObjectSet emptyArray = new ObjectSet<>(); public BlockIndexer(){ @@ -74,18 +95,18 @@ public class BlockIndexer { //create bitset for each team type that contains each quadrant structQuadrants = new Bits[Team.all.length]; - for(int i = 0; i < Team.all.length; i ++){ - structQuadrants[i] = new Bits(Mathf.ceil(world.width() / (float)structQuadrantSize) * Mathf.ceil(world.height() / (float)structQuadrantSize)); + for(int i = 0; i < Team.all.length; i++){ + structQuadrants[i] = new Bits(Mathf.ceil(world.width() / (float) structQuadrantSize) * Mathf.ceil(world.height() / (float) structQuadrantSize)); } - for(int x = 0; x < world.width(); x ++){ - for (int y = 0; y < world.height(); y++) { + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ process(world.tile(x, y)); } } - for (int x = 0; x < quadWidth(); x++) { - for (int y = 0; y < quadHeight(); y++) { + for(int x = 0; x < quadWidth(); x++){ + for(int y = 0; y < quadHeight(); y++){ updateQuadrant(world.tile(x * structQuadrantSize, y * structQuadrantSize)); } } @@ -94,12 +115,16 @@ public class BlockIndexer { }); } - /**Get all allied blocks with a flag.*/ + /** + * Get all allied blocks with a flag. + */ public ObjectSet getAllied(Team team, BlockFlag type){ return (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray); } - /**Get all enemy blocks with a flag.*/ + /** + * Get all enemy blocks with a flag. + */ public ObjectSet getEnemy(Team team, BlockFlag type){ return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray); } @@ -108,13 +133,13 @@ public class BlockIndexer { Entity closest = null; float dst = 0; - for(int rx = Math.max((int)((x-range)/tilesize/structQuadrantSize), 0); rx <= (int)((x+range)/tilesize/structQuadrantSize) && rx < quadWidth(); rx ++){ - for(int ry = Math.max((int)((y-range)/tilesize/structQuadrantSize), 0); ry <= (int)((y+range)/tilesize/structQuadrantSize) && ry < quadHeight(); ry ++){ + for(int rx = Math.max((int) ((x - range) / tilesize / structQuadrantSize), 0); rx <= (int) ((x + range) / tilesize / structQuadrantSize) && rx < quadWidth(); rx++){ + for(int ry = Math.max((int) ((y - range) / tilesize / structQuadrantSize), 0); ry <= (int) ((y + range) / tilesize / structQuadrantSize) && ry < quadHeight(); ry++){ if(!getQuad(team, rx, ry)) continue; - for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx ++){ - for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty ++ ){ + for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){ + for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){ Tile other = world.tile(tx, ty); if(other == null || other.entity == null || !pred.test(other)) continue; @@ -134,22 +159,26 @@ public class BlockIndexer { return (TileEntity) closest; } - /**Returns a set of tiles that have ores of the specified type nearby. + /** + * Returns a set of tiles that have ores of the specified type nearby. * While each tile in the set is not guaranteed to have an ore directly on it, * each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it. - * Only specific ore types are scanned. See {@link #scanOres}.*/ + * Only specific ore types are scanned. See {@link #scanOres}. + */ public ObjectSet getOrePositions(Item item){ return ores.get(item, emptyArray); } - /**Find the closest ore block relative to a position.*/ + /** + * Find the closest ore block relative to a position. + */ public Tile findClosestOre(float xp, float yp, Item item){ - Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item)); + Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item)); if(tile == null) return null; - for (int x = Math.max(0, tile.x - oreQuadrantSize/2); x < tile.x + oreQuadrantSize/2 && x < world.width(); x++) { - for (int y = Math.max(0, tile.y - oreQuadrantSize/2); y < tile.y + oreQuadrantSize/2 && y < world.height(); y++) { + for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){ + for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){ Tile res = world.tile(x, y); if(res.block() == Blocks.air && res.floor().drops != null && res.floor().drops.item == item){ return res; @@ -186,12 +215,12 @@ public class BlockIndexer { int quadrantY = tile.y / oreQuadrantSize; itemSet.clear(); - Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1), - Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1)); + Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1), + Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)); //find all items that this quadrant contains - for (int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++) { - for (int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++) { + for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){ + for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){ Tile result = world.tile(x, y); if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue; @@ -200,7 +229,7 @@ public class BlockIndexer { } //update quadrant at this position - for (Item item : scanOres){ + for(Item item : scanOres){ ObjectSet set = ores.get(item); //update quadrant status depending on whether the item is in it @@ -219,7 +248,7 @@ public class BlockIndexer { int index = quadrantX + quadrantY * quadWidth(); //Log.info("Updating quadrant: {0} {1}", quadrantX, quadrantY); - for(TeamData data : state.teams.getTeams()) { + for(TeamData data : state.teams.getTeams()){ //fast-set this quadrant to 'occupied' if the tile just placed is already of this team if(tile.getTeam() == data.team && tile.entity != null){ @@ -230,8 +259,8 @@ public class BlockIndexer { structQuadrants[data.team.ordinal()].clear(index); outer: - for (int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++) { - for (int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++) { + for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){ + for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){ Tile result = world.tile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching if(result.entity != null && result.getTeam() == data.team){ @@ -244,16 +273,16 @@ public class BlockIndexer { } private boolean getQuad(Team team, int quadrantX, int quadrantY){ - int index = quadrantX + quadrantY * Mathf.ceil(world.width() / (float)structQuadrantSize); + int index = quadrantX + quadrantY * Mathf.ceil(world.width() / (float) structQuadrantSize); return structQuadrants[team.ordinal()].get(index); } private int quadWidth(){ - return Mathf.ceil(world.width() / (float)structQuadrantSize); + return Mathf.ceil(world.width() / (float) structQuadrantSize); } private int quadHeight(){ - return Mathf.ceil(world.height() / (float)structQuadrantSize); + return Mathf.ceil(world.height() / (float) structQuadrantSize); } private ObjectMap> getMap(Team team){ @@ -269,10 +298,10 @@ public class BlockIndexer { ores.put(item, new ObjectSet<>()); } - for(int x = 0; x < world.width(); x ++){ - for (int y = 0; y < world.height(); y++) { - int qx = (x/ oreQuadrantSize); - int qy = (y/ oreQuadrantSize); + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ + int qx = (x / oreQuadrantSize); + int qy = (y / oreQuadrantSize); Tile tile = world.tile(x, y); @@ -280,8 +309,8 @@ public class BlockIndexer { if(tile.floor().drops != null && scanOres.contains(tile.floor().drops.item) && tile.block() == Blocks.air){ ores.get(tile.floor().drops.item).add(world.tile( //make sure to clamp quadrant middle position, since it might go off bounds - Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1), - Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1))); + Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1), + Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1))); } } } @@ -291,7 +320,7 @@ public class BlockIndexer { public final EnumSet flags; public final Team team; - public TileIndex(EnumSet flags, Team team) { + public TileIndex(EnumSet flags, Team team){ this.flags = flags; this.team = team; } diff --git a/core/src/io/anuke/mindustry/ai/Pathfinder.java b/core/src/io/anuke/mindustry/ai/Pathfinder.java index 81c6cf01c9..f3290674be 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -20,7 +20,7 @@ import io.anuke.ucore.util.Log; import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; -public class Pathfinder { +public class Pathfinder{ private long maxUpdate = TimeUtils.millisToNanos(4); private PathData[] paths; private IntArray blocked = new IntArray(); @@ -56,7 +56,7 @@ public class Pathfinder { Tile target = null; float tl = 0f; - for(GridPoint2 point : Geometry.d8) { + for(GridPoint2 point : Geometry.d8){ int dx = tile.x + point.x, dy = tile.y + point.y; Tile other = world.tile(dx, dy); @@ -89,16 +89,16 @@ public class Pathfinder { } private void update(Tile tile, Team team){ - if(paths[team.ordinal()] != null) { + if(paths[team.ordinal()] != null){ PathData path = paths[team.ordinal()]; if(!passable(tile, team)){ path.weights[tile.x][tile.y] = Float.MAX_VALUE; } - path.search ++; + path.search++; - if(path.lastSearchTime + 1000/60*3 > TimeUtils.millis()){ + if(path.lastSearchTime + 1000 / 60 * 3 > TimeUtils.millis()){ path.frontier.clear(); } @@ -115,17 +115,17 @@ public class Pathfinder { private void createFor(Team team){ PathData path = new PathData(); - path.search ++; + path.search++; path.frontier.ensureCapacity((world.width() + world.height()) * 3); paths[team.ordinal()] = path; - for (int x = 0; x < world.width(); x++) { - for (int y = 0; y < world.height(); y++) { + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ Tile tile = world.tile(x, y); - if (tile.block().flags != null && state.teams.areEnemies(tile.getTeam(), team) - && tile.block().flags.contains(BlockFlag.target)) { + if(tile.block().flags != null && state.teams.areEnemies(tile.getTeam(), team) + && tile.block().flags.contains(BlockFlag.target)){ path.frontier.addFirst(tile); path.weights[x][y] = 0; path.searches[x][y] = path.search; @@ -143,20 +143,20 @@ public class Pathfinder { long start = TimeUtils.nanoTime(); - while (path.frontier.size > 0 && (nsToRun < 0 || TimeUtils.timeSinceNanos(start) <= nsToRun)) { + while(path.frontier.size > 0 && (nsToRun < 0 || TimeUtils.timeSinceNanos(start) <= nsToRun)){ Tile tile = path.frontier.removeLast(); float cost = path.weights[tile.x][tile.y]; - if (cost < Float.MAX_VALUE) { - for (GridPoint2 point : Geometry.d4) { + if(cost < Float.MAX_VALUE){ + for(GridPoint2 point : Geometry.d4){ int dx = tile.x + point.x, dy = tile.y + point.y; Tile other = world.tile(dx, dy); - if (other != null && (path.weights[dx][dy] > cost + 1 || path.searches[dx][dy] < path.search) + if(other != null && (path.weights[dx][dy] > cost + 1 || path.searches[dx][dy] < path.search) && passable(other, team)){ path.frontier.addFirst(world.tile(dx, dy)); - path.weights[dx][dy] = cost + other.cost/2f; + path.weights[dx][dy] = cost + other.cost / 2f; path.searches[dx][dy] = path.search; } } diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java index ed9b8dd60d..96635c2576 100644 --- a/core/src/io/anuke/mindustry/ai/WaveSpawner.java +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -18,7 +18,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class WaveSpawner { +public class WaveSpawner{ private static final int quadsize = 4; private Bits quadrants; @@ -34,28 +34,28 @@ public class WaveSpawner { public void write(DataOutput output) throws IOException{ output.writeShort(flySpawns.size); - for (FlyerSpawn spawn : flySpawns){ + for(FlyerSpawn spawn : flySpawns){ output.writeFloat(spawn.angle); } output.writeShort(groundSpawns.size); - for (GroundSpawn spawn : groundSpawns){ - output.writeShort((short)spawn.x); - output.writeShort((short)spawn.y); + for(GroundSpawn spawn : groundSpawns){ + output.writeShort((short) spawn.x); + output.writeShort((short) spawn.y); } } public void read(DataInput input) throws IOException{ short flya = input.readShort(); - - for (int i = 0; i < flya; i++) { + + for(int i = 0; i < flya; i++){ FlyerSpawn spawn = new FlyerSpawn(); spawn.angle = input.readFloat(); flySpawns.add(spawn); } - + short grounda = input.readShort(); - for (int i = 0; i < grounda; i++) { + for(int i = 0; i < grounda; i++){ GroundSpawn spawn = new GroundSpawn(); spawn.x = input.readShort(); spawn.y = input.readShort(); @@ -80,13 +80,13 @@ public class WaveSpawner { int addGround = groundGroups - groundSpawns.size, addFly = flyGroups - flySpawns.size; //add extra groups if the total exceeds it - for (int i = 0; i < addGround; i++) { + for(int i = 0; i < addGround; i++){ GroundSpawn spawn = new GroundSpawn(); findLocation(spawn); groundSpawns.add(spawn); } - for (int i = 0; i < addFly; i++) { + for(int i = 0; i < addFly; i++){ FlyerSpawn spawn = new FlyerSpawn(); findLocation(spawn); flySpawns.add(spawn); @@ -99,7 +99,7 @@ public class WaveSpawner { int groups = group.getGroupsSpawned(state.wave); int spawned = group.getUnitsSpawned(state.wave); - for (int i = 0; i < groups; i++) { + for(int i = 0; i < groups; i++){ Squad squad = new Squad(); float spawnX, spawnY; float spread; @@ -109,11 +109,11 @@ public class WaveSpawner { //TODO verify flyer spawn float margin = 40f; //how far away from the edge flying units spawn - spawnX = world.width() *tilesize/2f + Mathf.sqrwavex(spawn.angle) * (world.width()/2f*tilesize + margin); - spawnY = world.height() * tilesize/2f + Mathf.sqrwavey(spawn.angle) * (world.height()/2f*tilesize + margin); + spawnX = world.width() * tilesize / 2f + Mathf.sqrwavex(spawn.angle) * (world.width() / 2f * tilesize + margin); + spawnY = world.height() * tilesize / 2f + Mathf.sqrwavey(spawn.angle) * (world.height() / 2f * tilesize + margin); spread = margin / 1.5f; - flyCount ++; + flyCount++; }else{ GroundSpawn spawn = groundSpawns.get(groundCount); checkQuadrant(spawn.x, spawn.y); @@ -121,14 +121,14 @@ public class WaveSpawner { findLocation(spawn); } - spawnX = spawn.x * quadsize * tilesize + quadsize * tilesize/2f; - spawnY = spawn.y * quadsize * tilesize + quadsize * tilesize/2f; - spread = quadsize*tilesize/3f; + spawnX = spawn.x * quadsize * tilesize + quadsize * tilesize / 2f; + spawnY = spawn.y * quadsize * tilesize + quadsize * tilesize / 2f; + spread = quadsize * tilesize / 3f; - groundCount ++; + groundCount++; } - for (int j = 0; j < spawned; j++) { + for(int j = 0; j < spawned; j++){ BaseUnit unit = group.createUnit(Team.red); unit.setWave(); unit.setSquad(squad); @@ -140,19 +140,19 @@ public class WaveSpawner { } public void checkAllQuadrants(){ - for(int x = 0; x < quadWidth(); x ++){ - for(int y = 0; y < quadHeight(); y ++){ + for(int x = 0; x < quadWidth(); x++){ + for(int y = 0; y < quadHeight(); y++){ checkQuadrant(x, y); } } } - + private void checkQuadrant(int quadx, int quady){ setQuad(quadx, quady, true); outer: - for (int x = quadx * quadsize; x < world.width() && x < (quadx + 1)*quadsize; x++) { - for (int y = quady * quadsize; y < world.height() && y < (quady + 1)*quadsize; y++) { + for(int x = quadx * quadsize; x < world.width() && x < (quadx + 1) * quadsize; x++){ + for(int y = quady * quadsize; y < world.height() && y < (quady + 1) * quadsize; y++){ Tile tile = world.tile(x, y); if(tile == null || tile.solid() || world.pathfinder().getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){ @@ -190,7 +190,7 @@ public class WaveSpawner { spawn.x = -1; spawn.y = -1; - int shellWidth = quadWidth()*2 + quadHeight() * 2 * 6; + int shellWidth = quadWidth() * 2 + quadHeight() * 2 * 6; shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth); Mathf.traverseSpiral(quadWidth(), quadHeight(), Mathf.random(shellWidth), (x, y) -> { @@ -210,11 +210,11 @@ public class WaveSpawner { } private int quadWidth(){ - return Mathf.ceil(world.width() / (float)quadsize); + return Mathf.ceil(world.width() / (float) quadsize); } private int quadHeight(){ - return Mathf.ceil(world.height() / (float)quadsize); + return Mathf.ceil(world.height() / (float) quadsize); } private class FlyerSpawn{ diff --git a/core/src/io/anuke/mindustry/content/AmmoTypes.java b/core/src/io/anuke/mindustry/content/AmmoTypes.java index eb8fefb1a0..1c784a4736 100644 --- a/core/src/io/anuke/mindustry/content/AmmoTypes.java +++ b/core/src/io/anuke/mindustry/content/AmmoTypes.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.AmmoType; import io.anuke.mindustry.type.ContentList; -public class AmmoTypes implements ContentList { +public class AmmoTypes implements ContentList{ public static AmmoType bulletTungsten, bulletLead, bulletCarbide, bulletThorium, bulletSilicon, bulletPyratite, shotgunTungsten, bombExplosive, bombIncendiary, bombOil, shellCarbide, flamerThermite, weaponMissile, flakLead, flakExplosive, flakPlastic, flakSurge, missileExplosive, missileIncindiary, missileSurge, @@ -17,41 +17,41 @@ public class AmmoTypes implements ContentList { basicFlame, lancerLaser, lightning, spectreLaser, meltdownLaser, fuseShotgun, oil, water, lava, cryofluid; @Override - public void load() { + public void load(){ //weapon specific - shotgunTungsten = new AmmoType(Items.tungsten, WeaponBullets.tungstenShotgun, 2) {{ + shotgunTungsten = new AmmoType(Items.tungsten, WeaponBullets.tungstenShotgun, 2){{ shootEffect = ShootFx.shootBig; smokeEffect = ShootFx.shootBigSmoke; recoil = 1f; }}; - shellCarbide = new AmmoType(Items.carbide, WeaponBullets.shellCarbide, 2) {{ + shellCarbide = new AmmoType(Items.carbide, WeaponBullets.shellCarbide, 2){{ shootEffect = ShootFx.shootBig; smokeEffect = ShootFx.shootBigSmoke; }}; - bombExplosive = new AmmoType(Items.blastCompound, WeaponBullets.bombExplosive, 3) {{ + bombExplosive = new AmmoType(Items.blastCompound, WeaponBullets.bombExplosive, 3){{ shootEffect = Fx.none; smokeEffect = Fx.none; }}; - bombIncendiary = new AmmoType(Items.pyratite, WeaponBullets.bombIncendiary, 3) {{ + bombIncendiary = new AmmoType(Items.pyratite, WeaponBullets.bombIncendiary, 3){{ shootEffect = Fx.none; smokeEffect = Fx.none; }}; - bombOil = new AmmoType(Items.coal, WeaponBullets.bombOil, 3) {{ + bombOil = new AmmoType(Items.coal, WeaponBullets.bombOil, 3){{ shootEffect = Fx.none; smokeEffect = Fx.none; }}; - flamerThermite = new AmmoType(Items.pyratite, TurretBullets.basicFlame, 3) {{ + flamerThermite = new AmmoType(Items.pyratite, TurretBullets.basicFlame, 3){{ shootEffect = ShootFx.shootSmallFlame; }}; - weaponMissile = new AmmoType(Items.carbide, MissileBullets.javelin, 2) {{ + weaponMissile = new AmmoType(Items.carbide, MissileBullets.javelin, 2){{ shootEffect = BulletFx.hitBulletSmall; smokeEffect = Fx.none; reloadMultiplier = 1.2f; @@ -59,37 +59,37 @@ public class AmmoTypes implements ContentList { //bullets - bulletLead = new AmmoType(Items.lead, StandardBullets.lead, 5) {{ + bulletLead = new AmmoType(Items.lead, StandardBullets.lead, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; reloadMultiplier = 1.6f; inaccuracy = 5f; }}; - bulletTungsten = new AmmoType(Items.tungsten, StandardBullets.tungsten, 2) {{ + bulletTungsten = new AmmoType(Items.tungsten, StandardBullets.tungsten, 2){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; reloadMultiplier = 0.8f; }}; - bulletCarbide = new AmmoType(Items.carbide, StandardBullets.carbide, 2) {{ + bulletCarbide = new AmmoType(Items.carbide, StandardBullets.carbide, 2){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; reloadMultiplier = 0.6f; }}; - bulletThorium = new AmmoType(Items.thorium, StandardBullets.thorium, 2) {{ + bulletThorium = new AmmoType(Items.thorium, StandardBullets.thorium, 2){{ shootEffect = ShootFx.shootBig; smokeEffect = ShootFx.shootBigSmoke; }}; - bulletSilicon = new AmmoType(Items.silicon, StandardBullets.homing, 5) {{ + bulletSilicon = new AmmoType(Items.silicon, StandardBullets.homing, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; reloadMultiplier = 1.4f; }}; - bulletPyratite = new AmmoType(Items.pyratite, StandardBullets.tracer, 3) {{ + bulletPyratite = new AmmoType(Items.pyratite, StandardBullets.tracer, 3){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; inaccuracy = 3f; @@ -97,71 +97,71 @@ public class AmmoTypes implements ContentList { //flak - flakLead = new AmmoType(Items.lead, FlakBullets.lead, 5) {{ + flakLead = new AmmoType(Items.lead, FlakBullets.lead, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; }}; - flakExplosive = new AmmoType(Items.blastCompound, FlakBullets.explosive, 5) {{ + flakExplosive = new AmmoType(Items.blastCompound, FlakBullets.explosive, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; }}; - flakPlastic = new AmmoType(Items.plastanium, FlakBullets.plastic, 5) {{ + flakPlastic = new AmmoType(Items.plastanium, FlakBullets.plastic, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; }}; - flakSurge = new AmmoType(Items.surgealloy, FlakBullets.surge, 5) {{ + flakSurge = new AmmoType(Items.surgealloy, FlakBullets.surge, 5){{ shootEffect = ShootFx.shootSmall; smokeEffect = ShootFx.shootSmallSmoke; }}; //missiles - missileExplosive = new AmmoType(Items.blastCompound, MissileBullets.explosive, 1) {{ + missileExplosive = new AmmoType(Items.blastCompound, MissileBullets.explosive, 1){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 1.2f; }}; - missileIncindiary = new AmmoType(Items.pyratite, MissileBullets.incindiary, 1) {{ + missileIncindiary = new AmmoType(Items.pyratite, MissileBullets.incindiary, 1){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 1.0f; }}; - missileSurge = new AmmoType(Items.surgealloy, MissileBullets.surge, 1) {{ + missileSurge = new AmmoType(Items.surgealloy, MissileBullets.surge, 1){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; }}; //artillery - artilleryCarbide = new AmmoType(Items.carbide, ArtilleryBullets.carbide, 2) {{ + artilleryCarbide = new AmmoType(Items.carbide, ArtilleryBullets.carbide, 2){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; }}; - artilleryPlastic = new AmmoType(Items.plastanium, ArtilleryBullets.plastic, 2) {{ + artilleryPlastic = new AmmoType(Items.plastanium, ArtilleryBullets.plastic, 2){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 1.4f; }}; - artilleryHoming = new AmmoType(Items.silicon, ArtilleryBullets.homing, 1) {{ + artilleryHoming = new AmmoType(Items.silicon, ArtilleryBullets.homing, 1){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 0.9f; }}; - artilleryIncindiary = new AmmoType(Items.pyratite, ArtilleryBullets.incindiary, 2) {{ + artilleryIncindiary = new AmmoType(Items.pyratite, ArtilleryBullets.incindiary, 2){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 1.2f; }}; - artilleryExplosive = new AmmoType(Items.blastCompound, ArtilleryBullets.explosive, 1) {{ + artilleryExplosive = new AmmoType(Items.blastCompound, ArtilleryBullets.explosive, 1){{ shootEffect = ShootFx.shootBig2; smokeEffect = ShootFx.shootBigSmoke2; reloadMultiplier = 1.6f; @@ -169,7 +169,7 @@ public class AmmoTypes implements ContentList { //flame - basicFlame = new AmmoType(Liquids.oil, TurretBullets.basicFlame, 0.3f) {{ + basicFlame = new AmmoType(Liquids.oil, TurretBullets.basicFlame, 0.3f){{ shootEffect = ShootFx.shootSmallFlame; }}; @@ -198,7 +198,7 @@ public class AmmoTypes implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return AmmoType.all(); } } diff --git a/core/src/io/anuke/mindustry/content/Items.java b/core/src/io/anuke/mindustry/content/Items.java index eabd520782..d9de2c5513 100644 --- a/core/src/io/anuke/mindustry/content/Items.java +++ b/core/src/io/anuke/mindustry/content/Items.java @@ -12,41 +12,41 @@ public class Items implements ContentList{ biomatter, sand, blastCompound, pyratite; @Override - public void load() { + public void load(){ - stone = new Item("stone", Color.valueOf("777777")) {{ + stone = new Item("stone", Color.valueOf("777777")){{ hardness = 3; }}; - tungsten = new Item("tungsten", Color.valueOf("a0b0c8")) {{ + tungsten = new Item("tungsten", Color.valueOf("a0b0c8")){{ type = ItemType.material; hardness = 1; cost = 0.75f; }}; - lead = new Item("lead", Color.valueOf("8e85a2")) {{ + lead = new Item("lead", Color.valueOf("8e85a2")){{ type = ItemType.material; hardness = 1; cost = 0.6f; }}; - coal = new Item("coal", Color.valueOf("272727")) {{ + coal = new Item("coal", Color.valueOf("272727")){{ explosiveness = 0.2f; flammability = 0.5f; hardness = 2; }}; - carbide = new Item("carbide", Color.valueOf("e2e2e2")) {{ + carbide = new Item("carbide", Color.valueOf("e2e2e2")){{ type = ItemType.material; }}; - titanium = new Item("titanium", Color.valueOf("8da1e3")) {{ + titanium = new Item("titanium", Color.valueOf("8da1e3")){{ type = ItemType.material; hardness = 3; cost = 1.1f; }}; - thorium = new Item("thorium", Color.valueOf("f9a3c7")) {{ + thorium = new Item("thorium", Color.valueOf("f9a3c7")){{ type = ItemType.material; explosiveness = 0.1f; hardness = 4; @@ -54,49 +54,49 @@ public class Items implements ContentList{ cost = 1.2f; }}; - silicon = new Item("silicon", Color.valueOf("53565c")) {{ + silicon = new Item("silicon", Color.valueOf("53565c")){{ type = ItemType.material; cost = 0.9f; }}; - plastanium = new Item("plastanium", Color.valueOf("e9ead3")) {{ + plastanium = new Item("plastanium", Color.valueOf("e9ead3")){{ type = ItemType.material; flammability = 0.1f; explosiveness = 0.1f; cost = 1.5f; }}; - phasematter = new Item("phase-matter", Color.valueOf("f4ba6e")) {{ + phasematter = new Item("phase-matter", Color.valueOf("f4ba6e")){{ type = ItemType.material; cost = 1.5f; }}; - surgealloy = new Item("surge-alloy", Color.valueOf("b4d5c7")) {{ + surgealloy = new Item("surge-alloy", Color.valueOf("b4d5c7")){{ type = ItemType.material; }}; - biomatter = new Item("biomatter", Color.valueOf("648b55")) {{ + biomatter = new Item("biomatter", Color.valueOf("648b55")){{ flammability = 0.4f; fluxiness = 0.2f; }}; - sand = new Item("sand", Color.valueOf("e3d39e")) {{ + sand = new Item("sand", Color.valueOf("e3d39e")){{ fluxiness = 0.5f; }}; - blastCompound = new Item("blast-compound", Color.valueOf("ff795e")) {{ + blastCompound = new Item("blast-compound", Color.valueOf("ff795e")){{ flammability = 0.2f; explosiveness = 0.6f; }}; - pyratite = new Item("pyratite", Color.valueOf("ffaa5f")) {{ + pyratite = new Item("pyratite", Color.valueOf("ffaa5f")){{ flammability = 0.7f; explosiveness = 0.2f; }}; } @Override - public Array getAll() { + public Array getAll(){ return Item.all(); } } diff --git a/core/src/io/anuke/mindustry/content/Liquids.java b/core/src/io/anuke/mindustry/content/Liquids.java index e543988bc8..e1311d4a78 100644 --- a/core/src/io/anuke/mindustry/content/Liquids.java +++ b/core/src/io/anuke/mindustry/content/Liquids.java @@ -6,20 +6,13 @@ import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; import io.anuke.mindustry.type.Liquid; -public class Liquids implements ContentList { - public static Liquid none, water, lava, oil, cryofluid; +public class Liquids implements ContentList{ + public static Liquid water, lava, oil, cryofluid; @Override - public void load() { + public void load(){ - none = new Liquid("none", Color.CLEAR){ - @Override - public boolean isHidden(){ - return true; - } - }; - - water = new Liquid("water", Color.valueOf("486acd")) { + water = new Liquid("water", Color.valueOf("486acd")){ { heatCapacity = 0.4f; tier = 0; @@ -27,7 +20,7 @@ public class Liquids implements ContentList { } }; - lava = new Liquid("lava", Color.valueOf("e37341")) { + lava = new Liquid("lava", Color.valueOf("e37341")){ { temperature = 0.8f; viscosity = 0.8f; @@ -36,7 +29,7 @@ public class Liquids implements ContentList { } }; - oil = new Liquid("oil", Color.valueOf("313131")) { + oil = new Liquid("oil", Color.valueOf("313131")){ { viscosity = 0.7f; flammability = 0.6f; @@ -46,10 +39,10 @@ public class Liquids implements ContentList { } }; - cryofluid = new Liquid("cryofluid", Color.SKY) { + cryofluid = new Liquid("cryofluid", Color.SKY){ { - heatCapacity = 0.75f; - temperature = 0.4f; + heatCapacity = 0.9f; + temperature = 0.25f; tier = 1; effect = StatusEffects.freezing; } @@ -57,7 +50,7 @@ public class Liquids implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return Liquid.all(); } } diff --git a/core/src/io/anuke/mindustry/content/Mechs.java b/core/src/io/anuke/mindustry/content/Mechs.java index 27097704dc..c946060560 100644 --- a/core/src/io/anuke/mindustry/content/Mechs.java +++ b/core/src/io/anuke/mindustry/content/Mechs.java @@ -8,14 +8,16 @@ import io.anuke.mindustry.type.ContentList; import io.anuke.mindustry.type.Mech; import io.anuke.mindustry.type.Upgrade; -public class Mechs implements ContentList { +public class Mechs implements ContentList{ public static Mech alpha, delta, tau, omega, dart, javelin, trident, halberd; - /**These are not new mechs, just re-assignments for convenience.*/ + /** + * These are not new mechs, just re-assignments for convenience. + */ public static Mech starterDesktop, starterMobile; @Override - public void load() { + public void load(){ alpha = new Mech("alpha-mech", false){{ drillPower = 1; @@ -48,7 +50,7 @@ public class Mechs implements ContentList { }}; dart = new Mech("dart-ship", true){{ - drillPower = -1; + drillPower = 1; speed = 0.4f; maxSpeed = 3f; drag = 0.1f; @@ -85,7 +87,7 @@ public class Mechs implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return Upgrade.all(); } } diff --git a/core/src/io/anuke/mindustry/content/Recipes.java b/core/src/io/anuke/mindustry/content/Recipes.java index 2ff0bea050..9bdae7e9ef 100644 --- a/core/src/io/anuke/mindustry/content/Recipes.java +++ b/core/src/io/anuke/mindustry/content/Recipes.java @@ -12,19 +12,19 @@ import static io.anuke.mindustry.type.Category.*; public class Recipes implements ContentList{ @Override - public void load (){ + public void load(){ //WALLS new Recipe(defense, DefenseBlocks.tungstenWall, new ItemStack(Items.tungsten, 12)); - new Recipe(defense, DefenseBlocks.tungstenWallLarge, new ItemStack(Items.tungsten, 12*4)); + new Recipe(defense, DefenseBlocks.tungstenWallLarge, new ItemStack(Items.tungsten, 12 * 4)); new Recipe(defense, DefenseBlocks.carbideWall, new ItemStack(Items.carbide, 12)); - new Recipe(defense, DefenseBlocks.carbideWallLarge, new ItemStack(Items.carbide, 12*4)); + new Recipe(defense, DefenseBlocks.carbideWallLarge, new ItemStack(Items.carbide, 12 * 4)); new Recipe(defense, DefenseBlocks.thoriumWall, new ItemStack(Items.thorium, 12)); - new Recipe(defense, DefenseBlocks.thoriumWallLarge, new ItemStack(Items.thorium, 12*4)); + new Recipe(defense, DefenseBlocks.thoriumWallLarge, new ItemStack(Items.thorium, 12 * 4)); new Recipe(defense, DefenseBlocks.door, new ItemStack(Items.carbide, 12), new ItemStack(Items.silicon, 8)); - new Recipe(defense, DefenseBlocks.doorLarge, new ItemStack(Items.carbide, 12*4), new ItemStack(Items.silicon, 8*4)); + new Recipe(defense, DefenseBlocks.doorLarge, new ItemStack(Items.carbide, 12 * 4), new ItemStack(Items.silicon, 8 * 4)); //TURRETS new Recipe(weapon, TurretBlocks.duo, new ItemStack(Items.tungsten, 40)); @@ -44,11 +44,11 @@ public class Recipes implements ContentList{ //starter lead transporation new Recipe(distribution, DistributionBlocks.junction, new ItemStack(Items.lead, 2)); - new Recipe(distribution, DistributionBlocks.router, new ItemStack(Items.lead, 6)); + new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.lead, 6)); //advanced carbide transporation - new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.carbide, 2), new ItemStack(Items.tungsten, 2)); - new Recipe(distribution, DistributionBlocks.multiplexer, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8)); + //new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.carbide, 2), new ItemStack(Items.tungsten, 2)); + new Recipe(distribution, DistributionBlocks.distributor, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8)); new Recipe(distribution, DistributionBlocks.sorter, new ItemStack(Items.carbide, 4), new ItemStack(Items.tungsten, 4)); new Recipe(distribution, DistributionBlocks.overflowGate, new ItemStack(Items.carbide, 4), new ItemStack(Items.tungsten, 8)); new Recipe(distribution, DistributionBlocks.bridgeConveyor, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8)); @@ -171,7 +171,6 @@ public class Recipes implements ContentList{ new Recipe(production, ProductionBlocks.oilextractor, new ItemStack(Items.titanium, 40), new ItemStack(Items.surgealloy, 40));*/ - //new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.carbide, 1)); @@ -282,7 +281,7 @@ public class Recipes implements ContentList{ } @Override - public Array getAll() { + public Array getAll(){ return Recipe.all(); } } diff --git a/core/src/io/anuke/mindustry/content/StatusEffects.java b/core/src/io/anuke/mindustry/content/StatusEffects.java index 91e46ce74e..f17656c2e3 100644 --- a/core/src/io/anuke/mindustry/content/StatusEffects.java +++ b/core/src/io/anuke/mindustry/content/StatusEffects.java @@ -3,30 +3,30 @@ package io.anuke.mindustry.content; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.content.fx.EnvironmentFx; import io.anuke.mindustry.entities.StatusController.StatusEntry; -import io.anuke.mindustry.game.Content; -import io.anuke.mindustry.type.StatusEffect; import io.anuke.mindustry.entities.Unit; +import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; +import io.anuke.mindustry.type.StatusEffect; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Mathf; -public class StatusEffects implements ContentList { +public class StatusEffects implements ContentList{ public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded; @Override - public void load() { + public void load(){ none = new StatusEffect(0); - burning = new StatusEffect(4 * 60f) { + burning = new StatusEffect(4 * 60f){ { oppositeScale = 0.5f; } @Override - public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) { - if (to == tarred) { + public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ + if(to == tarred){ unit.damage(1f); Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); return result.set(this, Math.min(time + newTime, baseDuration + tarred.baseDuration)); @@ -36,45 +36,45 @@ public class StatusEffects implements ContentList { } @Override - public void update(Unit unit, float time) { + public void update(Unit unit, float time){ unit.damagePeriodic(0.04f); - if (Mathf.chance(Timers.delta() * 0.2f)) { + if(Mathf.chance(Timers.delta() * 0.2f)){ Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); } } }; - freezing = new StatusEffect(5 * 60f) { + freezing = new StatusEffect(5 * 60f){ { oppositeScale = 0.4f; speedMultiplier = 0.7f; } @Override - public void update(Unit unit, float time) { + public void update(Unit unit, float time){ - if (Mathf.chance(Timers.delta() * 0.15f)) { + if(Mathf.chance(Timers.delta() * 0.15f)){ Effects.effect(EnvironmentFx.freezing, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); } } }; - wet = new StatusEffect(3 * 60f) { + wet = new StatusEffect(3 * 60f){ { oppositeScale = 0.5f; speedMultiplier = 0.999f; } @Override - public void update(Unit unit, float time) { - if (Mathf.chance(Timers.delta() * 0.15f)) { + public void update(Unit unit, float time){ + if(Mathf.chance(Timers.delta() * 0.15f)){ Effects.effect(EnvironmentFx.wet, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); } } }; - melting = new StatusEffect(5 * 60f) { + melting = new StatusEffect(5 * 60f){ { oppositeScale = 0.2f; speedMultiplier = 0.8f; @@ -82,8 +82,8 @@ public class StatusEffects implements ContentList { } @Override - public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) { - if (to == tarred) { + public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ + if(to == tarred){ return result.set(this, Math.min(time + newTime / 2f, baseDuration)); } @@ -91,30 +91,30 @@ public class StatusEffects implements ContentList { } @Override - public void update(Unit unit, float time) { + public void update(Unit unit, float time){ unit.damagePeriodic(0.3f); - if (Mathf.chance(Timers.delta() * 0.2f)) { + if(Mathf.chance(Timers.delta() * 0.2f)){ Effects.effect(EnvironmentFx.melting, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); } } }; - tarred = new StatusEffect(4 * 60f) { + tarred = new StatusEffect(4 * 60f){ { speedMultiplier = 0.6f; } @Override - public void update(Unit unit, float time) { - if (Mathf.chance(Timers.delta() * 0.15f)) { + public void update(Unit unit, float time){ + if(Mathf.chance(Timers.delta() * 0.15f)){ Effects.effect(EnvironmentFx.oily, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); } } @Override - public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) { - if (to == melting || to == burning) { + public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ + if(to == melting || to == burning){ return result.set(to, newTime + time); } @@ -122,7 +122,7 @@ public class StatusEffects implements ContentList { } }; - overdrive = new StatusEffect(6f) { + overdrive = new StatusEffect(6f){ { armorMultiplier = 0.95f; speedMultiplier = 1.05f; @@ -130,13 +130,13 @@ public class StatusEffects implements ContentList { } @Override - public void update(Unit unit, float time) { + public void update(Unit unit, float time){ //idle regen boosted unit.health += 0.01f * Timers.delta(); } }; - shielded = new StatusEffect(6f) { + shielded = new StatusEffect(6f){ { armorMultiplier = 3f; } @@ -149,7 +149,7 @@ public class StatusEffects implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return StatusEffect.all(); } } diff --git a/core/src/io/anuke/mindustry/content/UnitTypes.java b/core/src/io/anuke/mindustry/content/UnitTypes.java index 8f95a7c3c4..e17da55df6 100644 --- a/core/src/io/anuke/mindustry/content/UnitTypes.java +++ b/core/src/io/anuke/mindustry/content/UnitTypes.java @@ -6,11 +6,11 @@ import io.anuke.mindustry.entities.units.types.*; import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; -public class UnitTypes implements ContentList { +public class UnitTypes implements ContentList{ public static UnitType drone, scout, vtol, monsoon, titan, fabricator; @Override - public void load() { + public void load(){ drone = new UnitType("drone", Drone.class, Drone::new){{ isFlying = true; drag = 0.01f; @@ -73,7 +73,7 @@ public class UnitTypes implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return UnitType.all(); } } diff --git a/core/src/io/anuke/mindustry/content/Weapons.java b/core/src/io/anuke/mindustry/content/Weapons.java index e3b2321dfa..5ccc7456fc 100644 --- a/core/src/io/anuke/mindustry/content/Weapons.java +++ b/core/src/io/anuke/mindustry/content/Weapons.java @@ -8,13 +8,13 @@ import io.anuke.mindustry.type.ContentList; import io.anuke.mindustry.type.Upgrade; import io.anuke.mindustry.type.Weapon; -public class Weapons implements ContentList { +public class Weapons implements ContentList{ public static Weapon blaster, chainBlaster, shockgun, sapper, swarmer, bomber, flakgun, flamethrower, missiles; @Override - public void load() { + public void load(){ - blaster = new Weapon("blaster") {{ + blaster = new Weapon("blaster"){{ length = 1.5f; reload = 15f; roundrobin = true; @@ -22,7 +22,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.bulletLead); }}; - missiles = new Weapon("missiles") {{ + missiles = new Weapon("missiles"){{ length = 1.5f; reload = 40f; shots = 2; @@ -33,7 +33,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.weaponMissile); }}; - chainBlaster = new Weapon("chain-blaster") {{ + chainBlaster = new Weapon("chain-blaster"){{ length = 1.5f; reload = 30f; roundrobin = true; @@ -41,7 +41,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletTungsten, AmmoTypes.bulletSilicon, AmmoTypes.bulletThorium); }}; - shockgun = new Weapon("shockgun") {{ + shockgun = new Weapon("shockgun"){{ length = 1f; reload = 50f; roundrobin = true; @@ -53,7 +53,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.shotgunTungsten); }}; - flakgun = new Weapon("flakgun") {{ + flakgun = new Weapon("flakgun"){{ length = 1f; reload = 70f; roundrobin = true; @@ -65,7 +65,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.shellCarbide); }}; - flamethrower = new Weapon("flamethrower") {{ + flamethrower = new Weapon("flamethrower"){{ length = 1f; reload = 14f; roundrobin = true; @@ -74,7 +74,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.flamerThermite); }}; - sapper = new Weapon("sapper") {{ + sapper = new Weapon("sapper"){{ length = 1.5f; reload = 12f; roundrobin = true; @@ -82,7 +82,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.bulletCarbide); }}; - swarmer = new Weapon("swarmer") {{ + swarmer = new Weapon("swarmer"){{ length = 1.5f; reload = 10f; roundrobin = true; @@ -90,7 +90,7 @@ public class Weapons implements ContentList { setAmmo(AmmoTypes.bulletPyratite); }}; - bomber = new Weapon("bomber") {{ + bomber = new Weapon("bomber"){{ length = 0f; width = 2f; reload = 5f; @@ -103,7 +103,7 @@ public class Weapons implements ContentList { } @Override - public Array getAll() { + public Array getAll(){ return Upgrade.all(); } } diff --git a/core/src/io/anuke/mindustry/content/blocks/BlockList.java b/core/src/io/anuke/mindustry/content/blocks/BlockList.java index 9bf7eb92ee..e1b7819220 100644 --- a/core/src/io/anuke/mindustry/content/blocks/BlockList.java +++ b/core/src/io/anuke/mindustry/content/blocks/BlockList.java @@ -5,10 +5,10 @@ import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; import io.anuke.mindustry.world.Block; -public abstract class BlockList implements ContentList { +public abstract class BlockList implements ContentList{ @Override - public Array getAll() { + public Array getAll(){ return Block.all(); } } diff --git a/core/src/io/anuke/mindustry/content/blocks/Blocks.java b/core/src/io/anuke/mindustry/content/blocks/Blocks.java index cba522baa1..1268255a74 100644 --- a/core/src/io/anuke/mindustry/content/blocks/Blocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/Blocks.java @@ -15,26 +15,31 @@ public class Blocks extends BlockList implements ContentList{ public static Block air, spawn, blockpart, space, metalfloor, deepwater, water, lava, oil, stone, blackstone, dirt, sand, ice, snow, grass, shrub, rock, icerock, blackrock; - @Override - public void load() { - air = new Floor("air") { + public void load(){ + air = new Floor("air"){ { blend = false; } + //don't draw - public void draw(Tile tile) {} - public void load() {} - public void init() {} + public void draw(Tile tile){ + } + + public void load(){ + } + + public void init(){ + } }; blockpart = new BlockPart(); - for(int i = 1; i <= 6; i ++){ + for(int i = 1; i <= 6; i++){ new BuildBlock("build" + i); } - space = new Floor("space") {{ + space = new Floor("space"){{ placeableOn = false; variants = 0; cacheLayer = CacheLayer.space; @@ -43,11 +48,11 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("000001"); }}; - metalfloor = new Floor("metalfloor") {{ + metalfloor = new Floor("metalfloor"){{ variants = 6; }}; - deepwater = new Floor("deepwater") {{ + deepwater = new Floor("deepwater"){{ liquidColor = Color.valueOf("546bb3"); speedMultiplier = 0.2f; variants = 0; @@ -60,7 +65,7 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("465a96"); }}; - water = new Floor("water") {{ + water = new Floor("water"){{ liquidColor = Color.valueOf("546bb3"); speedMultiplier = 0.5f; variants = 0; @@ -72,7 +77,7 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("506eb4"); }}; - lava = new Floor("lava") {{ + lava = new Floor("lava"){{ liquidColor = Color.valueOf("ed5334"); speedMultiplier = 0.2f; damageTaken = 0.5f; @@ -85,7 +90,7 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("ed5334"); }}; - oil = new Floor("oil") {{ + oil = new Floor("oil"){{ liquidColor = Color.valueOf("292929"); status = StatusEffects.tarred; statusIntensity = 1f; @@ -97,7 +102,7 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("292929"); }}; - stone = new Floor("stone") {{ + stone = new Floor("stone"){{ hasOres = true; drops = new ItemStack(Items.stone, 1); blends = block -> block != this && !(block instanceof Ore); @@ -105,7 +110,7 @@ public class Blocks extends BlockList implements ContentList{ playerUnmineable = true; }}; - blackstone = new Floor("blackstone") {{ + blackstone = new Floor("blackstone"){{ drops = new ItemStack(Items.stone, 1); minimapColor = Color.valueOf("252525"); playerUnmineable = true; @@ -115,14 +120,14 @@ public class Blocks extends BlockList implements ContentList{ minimapColor = Color.valueOf("6e501e"); }}; - sand = new Floor("sand") {{ + sand = new Floor("sand"){{ drops = new ItemStack(Items.sand, 1); minimapColor = Color.valueOf("988a67"); hasOres = true; playerUnmineable = true; }}; - ice = new Floor("ice") {{ + ice = new Floor("ice"){{ dragMultiplier = 0.3f; speedMultiplier = 0.4f; minimapColor = Color.valueOf("c4e3e7"); @@ -143,19 +148,16 @@ public class Blocks extends BlockList implements ContentList{ shadow = "shrubshadow"; }}; - rock = new Rock("rock") {{ + rock = new Rock("rock"){{ variants = 2; - varyShadow = true; }}; - icerock = new Rock("icerock") {{ + icerock = new Rock("icerock"){{ variants = 2; - varyShadow = true; }}; - blackrock = new Rock("blackrock") {{ + blackrock = new Rock("blackrock"){{ variants = 1; - varyShadow = true; }}; } } diff --git a/core/src/io/anuke/mindustry/content/blocks/CraftingBlocks.java b/core/src/io/anuke/mindustry/content/blocks/CraftingBlocks.java index e0f8e9e4bd..67ab558fdd 100644 --- a/core/src/io/anuke/mindustry/content/blocks/CraftingBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/CraftingBlocks.java @@ -10,55 +10,54 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.production.*; -public class CraftingBlocks extends BlockList implements ContentList { +public class CraftingBlocks extends BlockList implements ContentList{ public static Block smelter, arcsmelter, siliconsmelter, plastaniumCompressor, phaseWeaver, alloysmelter, alloyfuser, pyratiteMixer, blastMixer, - cryofluidmixer, melter, separator, centrifuge, biomatterCompressor, pulverizer, oilRefinery, solidifier, incinerator; + cryofluidmixer, melter, separator, centrifuge, biomatterCompressor, pulverizer, solidifier, incinerator; @Override - public void load() { - smelter = new Smelter("smelter") {{ + public void load(){ + smelter = new Smelter("smelter"){{ health = 70; - inputs = new ItemStack[]{new ItemStack(Items.tungsten, 3)}; - fuel = Items.coal; result = Items.carbide; craftTime = 45f; burnDuration = 35f; useFlux = true; + + consumes.items(new ItemStack[]{new ItemStack(Items.tungsten, 3)}); + consumes.item(Items.coal); }}; - arcsmelter = new PowerSmelter("arc-smelter") {{ + arcsmelter = new PowerSmelter("arc-smelter"){{ health = 90; craftEffect = BlockFx.smeltsmoke; - inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.tungsten, 2)}; result = Items.carbide; - powerUse = 0.1f; craftTime = 30f; size = 2; useFlux = true; fluxNeeded = 2; + + consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.tungsten, 2)}); + consumes.power(0.1f); }}; - siliconsmelter = new PowerSmelter("silicon-smelter") {{ + siliconsmelter = new PowerSmelter("silicon-smelter"){{ health = 90; craftEffect = BlockFx.smeltsmoke; - inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.sand, 2)}; result = Items.silicon; - powerUse = 0.05f; craftTime = 40f; size = 2; hasLiquids = false; flameColor = Color.valueOf("ffef99"); + + consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.sand, 2)}); + consumes.power(0.05f); }}; - plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor") {{ - inputLiquid = Liquids.oil; - inputItem = new ItemStack(Items.titanium, 2); + plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor"){{ hasItems = true; - liquidUse = 0.3f; liquidCapacity = 60f; - powerUse = 0.5f; craftTime = 80f; output = Items.plastanium; itemCapacity = 30; @@ -67,94 +66,103 @@ public class CraftingBlocks extends BlockList implements ContentList { hasPower = hasLiquids = true; craftEffect = BlockFx.formsmoke; updateEffect = BlockFx.plasticburn; + + consumes.liquid(Liquids.oil, 0.3f); + consumes.power(0.4f); + consumes.item(Items.titanium, 2); }}; - phaseWeaver = new PhaseWeaver("phase-weaver") {{ + phaseWeaver = new PhaseWeaver("phase-weaver"){{ health = 90; craftEffect = BlockFx.smeltsmoke; - inputs = new ItemStack[]{new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10)}; result = Items.phasematter; - powerUse = 0.4f; craftTime = 120f; size = 2; + + consumes.items(new ItemStack[]{new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10)}); + consumes.power(0.5f); }}; - alloysmelter = new PowerSmelter("alloy-smelter") {{ + alloysmelter = new PowerSmelter("alloy-smelter"){{ health = 90; craftEffect = BlockFx.smeltsmoke; - inputs = new ItemStack[]{new ItemStack(Items.titanium, 2), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)}; result = Items.surgealloy; - powerUse = 0.3f; craftTime = 50f; size = 2; useFlux = true; fluxNeeded = 4; + + consumes.power(0.3f); + consumes.items(new ItemStack[]{new ItemStack(Items.titanium, 2), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)}); }}; - alloyfuser = new PowerSmelter("alloy-fuser") {{ + alloyfuser = new PowerSmelter("alloy-fuser"){{ health = 90; craftEffect = BlockFx.smeltsmoke; - inputs = new ItemStack[]{new ItemStack(Items.titanium, 3), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)}; result = Items.surgealloy; - powerUse = 0.4f; craftTime = 30f; size = 3; useFlux = true; fluxNeeded = 4; + + consumes.items(new ItemStack[]{new ItemStack(Items.titanium, 3), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)}); + consumes.power(0.4f); }}; - cryofluidmixer = new LiquidMixer("cryofluidmixer") {{ + cryofluidmixer = new LiquidMixer("cryofluidmixer"){{ health = 200; - inputLiquid = Liquids.water; outputLiquid = Liquids.cryofluid; - inputItem = Items.titanium; liquidPerItem = 50f; itemCapacity = 50; - powerUse = 0.1f; size = 2; + hasPower = true; + + consumes.power(0.1f); + consumes.item(Items.titanium); + consumes.liquid(Liquids.water, 0.3f); }}; - blastMixer = new GenericCrafter("blast-mixer") {{ + blastMixer = new GenericCrafter("blast-mixer"){{ itemCapacity = 20; hasItems = true; hasPower = true; - inputLiquid = Liquids.oil; - liquidUse = 0.05f; - inputItem = new ItemStack(Items.pyratite, 1); + hasLiquids = true; output = Items.blastCompound; - powerUse = 0.04f; - size = 2; + + consumes.liquid(Liquids.oil, 0.05f); + consumes.item(Items.pyratite, 1); + consumes.power(0.04f); }}; - pyratiteMixer = new PowerSmelter("pyratite-mixer") {{ + pyratiteMixer = new PowerSmelter("pyratite-mixer"){{ flameColor = Color.CLEAR; itemCapacity = 20; hasItems = true; hasPower = true; - inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.lead, 2), new ItemStack(Items.sand, 2)}; result = Items.pyratite; - powerUse = 0.02f; size = 2; + + consumes.power(0.02f); + consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.lead, 2), new ItemStack(Items.sand, 2)}); }}; - melter = new PowerCrafter("melter") {{ + melter = new PowerCrafter("melter"){{ health = 200; outputLiquid = Liquids.lava; - outputLiquidAmount = 0.05f; - input = new ItemStack(Items.stone, 1); + outputLiquidAmount = 0.75f; itemCapacity = 50; craftTime = 10f; - powerUse = 0.1f; hasLiquids = hasPower = true; + + consumes.power(0.1f); + consumes.item(Items.stone, 2); }}; - separator = new Separator("separator") {{ - liquid = Liquids.water; - item = Items.stone; + separator = new Separator("separator"){{ results = new Item[]{ null, null, null, null, null, null, null, null, null, null, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, @@ -164,15 +172,15 @@ public class CraftingBlocks extends BlockList implements ContentList { Items.coal, Items.coal, Items.titanium }; - liquidUse = 0.2f; filterTime = 40f; itemCapacity = 40; health = 50; + + consumes.item(Items.stone, 2); + consumes.liquid(Liquids.water, 0.3f); }}; - centrifuge = new Separator("centrifuge") {{ - liquid = Liquids.water; - item = Items.stone; + centrifuge = new Separator("centrifuge"){{ results = new Item[]{ null, null, null, null, null, null, null, null, null, null, null, null, null, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, @@ -184,9 +192,7 @@ public class CraftingBlocks extends BlockList implements ContentList { Items.thorium, }; - liquidUse = 0.3f; hasPower = true; - powerUse = 0.2f; filterTime = 15f; itemCapacity = 60; health = 50 * 4; @@ -195,56 +201,52 @@ public class CraftingBlocks extends BlockList implements ContentList { spinnerThickness = 1.5f; spinnerSpeed = 3f; size = 2; + + consumes.item(Items.stone, 2); + consumes.power(0.2f); + consumes.liquid(Liquids.water, 0.5f); }}; - biomatterCompressor = new Compressor("biomattercompressor") {{ - input = new ItemStack(Items.biomatter, 1); + biomatterCompressor = new Compressor("biomattercompressor"){{ liquidCapacity = 60f; itemCapacity = 50; - powerUse = 0.06f; craftTime = 25f; outputLiquid = Liquids.oil; - outputLiquidAmount = 0.1f; + outputLiquidAmount = 0.14f; size = 2; health = 320; hasLiquids = true; + + consumes.item(Items.biomatter, 1); + consumes.power(0.06f); }}; - pulverizer = new Pulverizer("pulverizer") {{ - inputItem = new ItemStack(Items.stone, 2); + pulverizer = new Pulverizer("pulverizer"){{ itemCapacity = 40; - powerUse = 0.2f; output = Items.sand; health = 80; craftEffect = BlockFx.pulverize; craftTime = 60f; updateEffect = BlockFx.pulverizeSmall; hasItems = hasPower = true; + + consumes.item(Items.stone, 2); + consumes.power(0.2f); }}; - oilRefinery = new GenericCrafter("oilrefinery") {{ - inputLiquid = Liquids.oil; - powerUse = 0.05f; - liquidUse = 0.1f; - liquidCapacity = 56f; - output = Items.coal; - health = 80; - craftEffect = BlockFx.purifyoil; - hasItems = hasLiquids = hasPower = true; - }}; - - solidifier = new GenericCrafter("solidifer") {{ - inputLiquid = Liquids.lava; - liquidUse = 1f; + solidifier = new GenericCrafter("solidifer"){{ liquidCapacity = 21f; craftTime = 14; output = Items.stone; + itemCapacity = 20; health = 80; craftEffect = BlockFx.purifystone; hasLiquids = hasItems = true; + + consumes.liquid(Liquids.lava, 1f); }}; - incinerator = new Incinerator("incinerator") {{ + incinerator = new Incinerator("incinerator"){{ health = 90; }}; } diff --git a/core/src/io/anuke/mindustry/content/blocks/DebugBlocks.java b/core/src/io/anuke/mindustry/content/blocks/DebugBlocks.java index 023e8bbc3c..b23a545823 100644 --- a/core/src/io/anuke/mindustry/content/blocks/DebugBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/DebugBlocks.java @@ -28,45 +28,52 @@ import java.io.IOException; public class DebugBlocks extends BlockList implements ContentList{ public static Block powerVoid, powerInfinite, itemSource, liquidSource, itemVoid; + @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) + public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){ + LiquidSourceEntity entity = tile.entity(); + entity.source = liquid; + } + @Override - public void load() { - powerVoid = new PowerBlock("powervoid") { + public void load(){ + powerVoid = new PowerBlock("powervoid"){ { powerCapacity = Float.MAX_VALUE; } }; - powerInfinite = new PowerNode("powerinfinite") { + powerInfinite = new PowerNode("powerinfinite"){ { powerCapacity = 10000f; powerSpeed = 100f; } @Override - public void update(Tile tile) { + public void update(Tile tile){ super.update(tile); tile.entity.power.amount = powerCapacity; } }; - itemSource = new Sorter("itemsource") { + itemSource = new Sorter("itemsource"){ { hasItems = true; } + @Override - public void update(Tile tile) { + public void update(Tile tile){ SorterEntity entity = tile.entity(); - entity.items.items[entity.sortItem.id] = 1; + entity.items.set(entity.sortItem, 1); tryDump(tile, entity.sortItem); } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return false; } }; - liquidSource = new Block("liquidsource") { + liquidSource = new Block("liquidsource"){ { update = true; solid = true; @@ -76,16 +83,15 @@ public class DebugBlocks extends BlockList implements ContentList{ } @Override - public void update(Tile tile) { + public void update(Tile tile){ LiquidSourceEntity entity = tile.entity(); - tile.entity.liquids.amount = liquidCapacity; - tile.entity.liquids.liquid = entity.source; - tryDumpLiquid(tile); + tile.entity.liquids.add(entity.source, liquidCapacity); + tryDumpLiquid(tile, entity.source); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ super.draw(tile); LiquidSourceEntity entity = tile.entity(); @@ -96,7 +102,7 @@ public class DebugBlocks extends BlockList implements ContentList{ } @Override - public void buildTable(Tile tile, Table table) { + public void buildTable(Tile tile, Table table){ LiquidSourceEntity entity = tile.entity(); Array items = Liquid.all(); @@ -104,8 +110,8 @@ public class DebugBlocks extends BlockList implements ContentList{ ButtonGroup group = new ButtonGroup<>(); Table cont = new Table(); - for (int i = 0; i < items.size; i++) { - if (i == 0) continue; + for(int i = 0; i < items.size; i++){ + if(i == 0) continue; final int f = i; ImageButton button = cont.addImageButton("white", "toggle", 24, () -> { CallBlocks.setLiquidSourceLiquid(null, tile, items.get(f)); @@ -113,7 +119,7 @@ public class DebugBlocks extends BlockList implements ContentList{ button.getStyle().imageUpColor = items.get(i).color; button.setChecked(entity.source.id == f); - if (i % 4 == 3) { + if(i % 4 == 3){ cont.row(); } } @@ -122,43 +128,37 @@ public class DebugBlocks extends BlockList implements ContentList{ } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new LiquidSourceEntity(); } }; - itemVoid = new Block("itemvoid") { + itemVoid = new Block("itemvoid"){ { update = solid = true; } @Override - public void handleItem(Item item, Tile tile, Tile source) { + public void handleItem(Item item, Tile tile, Tile source){ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return true; } }; } - @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) - public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){ - LiquidSourceEntity entity = tile.entity(); - entity.source = liquid; - } - - class LiquidSourceEntity extends TileEntity { + class LiquidSourceEntity extends TileEntity{ public Liquid source = Liquids.water; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeByte(source.id); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ source = Liquid.getByID(stream.readByte()); } } diff --git a/core/src/io/anuke/mindustry/content/blocks/DefenseBlocks.java b/core/src/io/anuke/mindustry/content/blocks/DefenseBlocks.java index 709e27ffd4..ca40928d80 100644 --- a/core/src/io/anuke/mindustry/content/blocks/DefenseBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/DefenseBlocks.java @@ -8,65 +8,65 @@ import io.anuke.mindustry.world.blocks.defense.DeflectorWall; import io.anuke.mindustry.world.blocks.defense.Door; import io.anuke.mindustry.world.blocks.defense.PhaseWall; -public class DefenseBlocks extends BlockList implements ContentList { +public class DefenseBlocks extends BlockList implements ContentList{ public static Block tungstenWall, tungstenWallLarge, carbideWall, carbideWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge, deflectorwall, deflectorwalllarge, - phasewall, phasewalllarge; + phasewall, phasewalllarge; @Override - public void load() { + public void load(){ int wallHealthMultiplier = 4; - tungstenWall = new Wall("tungsten-wall") {{ + tungstenWall = new Wall("tungsten-wall"){{ health = 80 * wallHealthMultiplier; }}; - tungstenWallLarge = new Wall("tungsten-wall-large") {{ + tungstenWallLarge = new Wall("tungsten-wall-large"){{ health = 80 * 4 * wallHealthMultiplier; size = 2; }}; - carbideWall = new Wall("carbide-wall") {{ + carbideWall = new Wall("carbide-wall"){{ health = 110 * wallHealthMultiplier; }}; - carbideWallLarge = new Wall("carbide-wall-large") {{ - health = 110 * wallHealthMultiplier*4; + carbideWallLarge = new Wall("carbide-wall-large"){{ + health = 110 * wallHealthMultiplier * 4; size = 2; }}; - thoriumWall = new Wall("thorium-wall") {{ - health = 110 * wallHealthMultiplier; + thoriumWall = new Wall("thorium-wall"){{ + health = 200 * wallHealthMultiplier; }}; - thoriumWallLarge = new Wall("thorium-wall-large") {{ - health = 110 * wallHealthMultiplier*4; + thoriumWallLarge = new Wall("thorium-wall-large"){{ + health = 200 * wallHealthMultiplier * 4; size = 2; }}; - deflectorwall = new DeflectorWall("deflector-wall") {{ + deflectorwall = new DeflectorWall("deflector-wall"){{ health = 150 * wallHealthMultiplier; }}; - deflectorwalllarge = new DeflectorWall("deflector-wall-large") {{ + deflectorwalllarge = new DeflectorWall("deflector-wall-large"){{ health = 150 * 4 * wallHealthMultiplier; size = 2; }}; - phasewall = new PhaseWall("phase-wall") {{ + phasewall = new PhaseWall("phase-wall"){{ health = 150 * wallHealthMultiplier; }}; - phasewalllarge = new PhaseWall("phase-wall-large") {{ + phasewalllarge = new PhaseWall("phase-wall-large"){{ health = 150 * 4 * wallHealthMultiplier; size = 2; regenSpeed = 0.5f; }}; - door = new Door("door") {{ + door = new Door("door"){{ health = 100 * wallHealthMultiplier; }}; - doorLarge = new Door("door-large") {{ + doorLarge = new Door("door-large"){{ openfx = BlockFx.dooropenlarge; closefx = BlockFx.doorcloselarge; health = 100 * 4 * wallHealthMultiplier; diff --git a/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java b/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java index 0db8445d7c..b5bbf1ad52 100644 --- a/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java @@ -5,53 +5,51 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.distribution.*; public class DistributionBlocks extends BlockList implements ContentList{ - public static Block conveyor, titaniumconveyor, router, multiplexer, junction, - bridgeConveyor, phaseConveyor, sorter, splitter, overflowGate, massDriver; + public static Block conveyor, titaniumconveyor, distributor, junction, + bridgeConveyor, phaseConveyor, sorter, splitter, overflowGate, massDriver; - @Override - public void load() { + @Override + public void load(){ - conveyor = new Conveyor("conveyor") {{ - health = 45; - speed = 0.03f; - }}; + conveyor = new Conveyor("conveyor"){{ + health = 45; + speed = 0.03f; + }}; - titaniumconveyor = new Conveyor("titanium-conveyor") {{ - health = 65; - speed = 0.07f; - }}; + titaniumconveyor = new Conveyor("titanium-conveyor"){{ + health = 65; + speed = 0.07f; + }}; - router = new Router("router"); + junction = new Junction("junction"){{ + speed = 26; + capacity = 32; + }}; - multiplexer = new Router("multiplexer") {{ - size = 2; - itemCapacity = 80; - }}; + bridgeConveyor = new BufferedItemBridge("bridge-conveyor"){{ + range = 3; + }}; - junction = new Junction("junction") {{ - speed = 26; - capacity = 32; - }}; + phaseConveyor = new ItemBridge("phase-conveyor"){{ + range = 7; + hasPower = false; + consumes.power(0.05f); + }}; - bridgeConveyor = new BufferedItemBridge("bridge-conveyor") {{ - range = 3; - hasPower = false; - }}; + sorter = new Sorter("sorter"); - phaseConveyor = new ItemBridge("phase-conveyor") {{ - range = 7; - }}; + splitter = new Splitter("splitter"); - sorter = new Sorter("sorter"); + distributor = new Splitter("distributor"){{ + size = 2; + }}; - splitter = new Splitter("splitter"); + overflowGate = new OverflowGate("overflow-gate"); - overflowGate = new OverflowGate("overflow-gate"); - - massDriver = new MassDriver("mass-driver"){{ - size = 3; - itemCapacity = 80; - range = 300f; - }}; - } + massDriver = new MassDriver("mass-driver"){{ + size = 3; + itemCapacity = 80; + range = 300f; + }}; + } } diff --git a/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java b/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java index 6b47cb80d4..8634381425 100644 --- a/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java @@ -9,46 +9,47 @@ public class LiquidBlocks extends BlockList implements ContentList{ public static Block mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidtank, liquidJunction, bridgeConduit, phaseConduit; @Override - public void load() { + public void load(){ - mechanicalPump = new Pump("mechanical-pump") {{ + mechanicalPump = new Pump("mechanical-pump"){{ shadow = "shadow-round-1"; pumpAmount = 0.1f; tier = 0; }}; - rotaryPump = new Pump("rotary-pump") {{ + rotaryPump = new Pump("rotary-pump"){{ shadow = "shadow-rounded-2"; pumpAmount = 0.25f; - powerUse = 0.015f; + consumes.power(0.015f); liquidCapacity = 30f; + hasPower = true; size = 2; tier = 1; }}; - thermalPump = new Pump("thermal-pump") {{ + thermalPump = new Pump("thermal-pump"){{ pumpAmount = 0.3f; - powerUse = 0.02f; + consumes.power(0.05f); liquidCapacity = 40f; size = 2; tier = 2; }}; - conduit = new Conduit("conduit") {{ + conduit = new Conduit("conduit"){{ health = 45; }}; - pulseConduit = new Conduit("pulse-conduit") {{ + pulseConduit = new Conduit("pulse-conduit"){{ liquidCapacity = 16f; liquidFlowFactor = 4.9f; health = 90; }}; - liquidRouter = new LiquidRouter("liquid-router") {{ + liquidRouter = new LiquidRouter("liquid-router"){{ liquidCapacity = 40f; }}; - liquidtank = new LiquidRouter("liquid-tank") {{ + liquidtank = new LiquidRouter("liquid-tank"){{ size = 3; liquidCapacity = 1500f; health = 500; @@ -56,13 +57,15 @@ public class LiquidBlocks extends BlockList implements ContentList{ liquidJunction = new LiquidJunction("liquid-junction"); - bridgeConduit = new LiquidExtendingBridge("bridge-conduit") {{ + bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{ range = 3; hasPower = false; }}; - phaseConduit = new LiquidBridge("phase-conduit") {{ + phaseConduit = new LiquidBridge("phase-conduit"){{ range = 7; + hasPower = false; + consumes.power(0.05f); }}; } } diff --git a/core/src/io/anuke/mindustry/content/blocks/OreBlocks.java b/core/src/io/anuke/mindustry/content/blocks/OreBlocks.java index cd1764586b..4cb86032f8 100644 --- a/core/src/io/anuke/mindustry/content/blocks/OreBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/OreBlocks.java @@ -7,11 +7,18 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.Floor; import io.anuke.mindustry.world.blocks.OreBlock; -public class OreBlocks extends BlockList { +public class OreBlocks extends BlockList{ private static final ObjectMap> oreBlockMap = new ObjectMap<>(); + public static Block get(Block floor, Item item){ + if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!"); + if(!oreBlockMap.get(item).containsKey(floor)) + throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!"); + return oreBlockMap.get(item).get(floor); + } + @Override - public void load() { + public void load(){ Item[] ores = {Items.tungsten, Items.lead, Items.coal, Items.titanium, Items.thorium}; for(Item item : ores){ @@ -25,10 +32,4 @@ public class OreBlocks extends BlockList { } } } - - public static Block get(Block floor, Item item){ - if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!"); - if(!oreBlockMap.get(item).containsKey(floor)) throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!"); - return oreBlockMap.get(item).get(floor); - } } diff --git a/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java b/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java index e8533325f7..df8ead1a55 100644 --- a/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java @@ -1,24 +1,25 @@ package io.anuke.mindustry.content.blocks; +import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.type.ContentList; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.distribution.WarpGate; import io.anuke.mindustry.world.blocks.power.*; -public class PowerBlocks extends BlockList implements ContentList { +public class PowerBlocks extends BlockList implements ContentList{ public static Block combustionGenerator, thermalGenerator, turbineGenerator, rtgGenerator, solarPanel, largeSolarPanel, nuclearReactor, fusionReactor, battery, batteryLarge, powerNode, powerNodeLarge, warpGate; @Override - public void load() { - combustionGenerator = new BurnerGenerator("combustion-generator") {{ + public void load(){ + combustionGenerator = new BurnerGenerator("combustion-generator"){{ powerOutput = 0.09f; powerCapacity = 40f; itemDuration = 40f; }}; - thermalGenerator = new LiquidHeatGenerator("thermal-generator") {{ + thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{ maxLiquidGenerate = 0.5f; powerPerLiquid = 0.08f; powerCapacity = 40f; @@ -27,55 +28,55 @@ public class PowerBlocks extends BlockList implements ContentList { size = 2; }}; - turbineGenerator = new TurbineGenerator("turbine-generator") {{ + turbineGenerator = new TurbineGenerator("turbine-generator"){{ powerOutput = 0.28f; powerCapacity = 40f; itemDuration = 30f; powerPerLiquid = 0.7f; - auxLiquidUse = 0.05f; + consumes.liquid(Liquids.water, 0.05f); size = 2; }}; - rtgGenerator = new DecayGenerator("rtg-generator") {{ + rtgGenerator = new DecayGenerator("rtg-generator"){{ powerCapacity = 40f; powerOutput = 0.02f; itemDuration = 500f; }}; - solarPanel = new SolarGenerator("solar-panel") {{ + solarPanel = new SolarGenerator("solar-panel"){{ generation = 0.0045f; }}; - largeSolarPanel = new SolarGenerator("solar-panel-large") {{ + largeSolarPanel = new SolarGenerator("solar-panel-large"){{ size = 3; generation = 0.055f; }}; - nuclearReactor = new NuclearReactor("nuclear-reactor") {{ + nuclearReactor = new NuclearReactor("nuclear-reactor"){{ size = 3; health = 700; powerMultiplier = 0.8f; }}; - fusionReactor = new FusionReactor("fusion-reactor") {{ + fusionReactor = new FusionReactor("fusion-reactor"){{ size = 4; health = 600; }}; - battery = new PowerDistributor("battery") {{ + battery = new PowerDistributor("battery"){{ powerCapacity = 320f; }}; - batteryLarge = new PowerDistributor("battery-large") {{ + batteryLarge = new PowerDistributor("battery-large"){{ size = 3; powerCapacity = 2000f; }}; - powerNode = new PowerNode("power-node") {{ + powerNode = new PowerNode("power-node"){{ shadow = "shadow-round-1"; }}; - powerNodeLarge = new PowerNode("power-node-large") {{ + powerNodeLarge = new PowerNode("power-node-large"){{ size = 2; powerSpeed = 1f; maxNodes = 5; diff --git a/core/src/io/anuke/mindustry/content/blocks/ProductionBlocks.java b/core/src/io/anuke/mindustry/content/blocks/ProductionBlocks.java index 6a7c9f8a18..c07dc66303 100644 --- a/core/src/io/anuke/mindustry/content/blocks/ProductionBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/ProductionBlocks.java @@ -11,35 +11,35 @@ import io.anuke.mindustry.world.blocks.production.Drill; import io.anuke.mindustry.world.blocks.production.Fracker; import io.anuke.mindustry.world.blocks.production.SolidPump; -public class ProductionBlocks extends BlockList implements ContentList { +public class ProductionBlocks extends BlockList implements ContentList{ public static Block tungstenDrill, carbideDrill, laserdrill, blastdrill, plasmadrill, waterextractor, oilextractor, cultivator; @Override - public void load() { - tungstenDrill = new Drill("tungsten-drill") {{ + public void load(){ + tungstenDrill = new Drill("tungsten-drill"){{ tier = 2; drillTime = 340; }}; - carbideDrill = new Drill("carbide-drill") {{ + carbideDrill = new Drill("carbide-drill"){{ tier = 3; drillTime = 280; }}; - laserdrill = new Drill("laser-drill") {{ + laserdrill = new Drill("laser-drill"){{ drillTime = 180; size = 2; - powerUse = 0.2f; hasPower = true; tier = 4; updateEffect = BlockFx.pulverizeMedium; drillEffect = BlockFx.mineBig; + + consumes.power(0.2f); }}; - blastdrill = new Drill("blast-drill") {{ + blastdrill = new Drill("blast-drill"){{ drillTime = 120; size = 3; - powerUse = 0.5f; drawRim = true; hasPower = true; tier = 5; @@ -48,13 +48,14 @@ public class ProductionBlocks extends BlockList implements ContentList { drillEffect = BlockFx.mineHuge; rotateSpeed = 6f; warmupSpeed = 0.01f; + + consumes.power(0.5f); }}; - plasmadrill = new Drill("plasma-drill") {{ + plasmadrill = new Drill("plasma-drill"){{ heatColor = Color.valueOf("ff461b"); drillTime = 90; size = 4; - powerUse = 0.7f; hasLiquids = true; hasPower = true; tier = 5; @@ -64,38 +65,43 @@ public class ProductionBlocks extends BlockList implements ContentList { updateEffectChance = 0.04f; drillEffect = BlockFx.mineHuge; warmupSpeed = 0.005f; + + consumes.power(0.7f); }}; - waterextractor = new SolidPump("water-extractor") {{ + waterextractor = new SolidPump("water-extractor"){{ result = Liquids.water; - powerUse = 0.2f; pumpAmount = 0.1f; size = 2; liquidCapacity = 30f; rotateSpeed = 1.4f; + + consumes.power(0.2f); }}; - oilextractor = new Fracker("oil-extractor") {{ + oilextractor = new Fracker("oil-extractor"){{ result = Liquids.oil; - inputLiquid = Liquids.water; updateEffect = BlockFx.pulverize; liquidCapacity = 50f; updateEffectChance = 0.05f; - inputLiquidUse = 0.3f; - powerUse = 0.6f; - pumpAmount = 0.06f; + pumpAmount = 0.08f; size = 3; liquidCapacity = 30f; + + consumes.item(Items.sand); + consumes.power(0.5f); + consumes.liquid(Liquids.water, 0.3f); }}; - cultivator = new Cultivator("cultivator") {{ + cultivator = new Cultivator("cultivator"){{ result = Items.biomatter; - inputLiquid = Liquids.water; - liquidUse = 0.2f; drillTime = 260; size = 2; hasLiquids = true; hasPower = true; + + consumes.power(0.08f); + consumes.liquid(Liquids.water, 0.2f); }}; } diff --git a/core/src/io/anuke/mindustry/content/blocks/StorageBlocks.java b/core/src/io/anuke/mindustry/content/blocks/StorageBlocks.java index 4e5a2953c9..d3946f8339 100644 --- a/core/src/io/anuke/mindustry/content/blocks/StorageBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/StorageBlocks.java @@ -7,25 +7,26 @@ import io.anuke.mindustry.world.blocks.storage.SortedUnloader; import io.anuke.mindustry.world.blocks.storage.Unloader; import io.anuke.mindustry.world.blocks.storage.Vault; -public class StorageBlocks extends BlockList implements ContentList { +public class StorageBlocks extends BlockList implements ContentList{ public static Block core, vault, unloader, sortedunloader; @Override - public void load() { - core = new CoreBlock("core") {{ + public void load(){ + core = new CoreBlock("core"){{ health = 800; }}; - vault = new Vault("vault") {{ + vault = new Vault("vault"){{ size = 3; health = 600; + itemCapacity = 2000; }}; - unloader = new Unloader("unloader") {{ + unloader = new Unloader("unloader"){{ speed = 5; }}; - sortedunloader = new SortedUnloader("sortedunloader") {{ + sortedunloader = new SortedUnloader("sortedunloader"){{ speed = 5; }}; } diff --git a/core/src/io/anuke/mindustry/content/blocks/TurretBlocks.java b/core/src/io/anuke/mindustry/content/blocks/TurretBlocks.java index 616dea4e7e..e408d82719 100644 --- a/core/src/io/anuke/mindustry/content/blocks/TurretBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/TurretBlocks.java @@ -12,22 +12,23 @@ import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Strings; -public class TurretBlocks extends BlockList implements ContentList { - public static Block duo, /*scatter,*/ scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown; +public class TurretBlocks extends BlockList implements ContentList{ + public static Block duo, /*scatter,*/ + scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown; - @Override - public void load() { - duo = new DoubleTurret("duo") {{ - ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletSilicon}; - reload = 25f; - restitution = 0.03f; - range = 90f; - shootCone = 15f; - ammoUseEffect = ShootFx.shellEjectSmall; - health = 80; - inaccuracy = 2f; - rotatespeed = 10f; - }}; + @Override + public void load(){ + duo = new DoubleTurret("duo"){{ + ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletSilicon}; + reload = 25f; + restitution = 0.03f; + range = 90f; + shootCone = 15f; + ammoUseEffect = ShootFx.shellEjectSmall; + health = 80; + inaccuracy = 2f; + rotatespeed = 10f; + }}; /* scatter = new BurstTurret("scatter") {{ ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic}; @@ -41,165 +42,165 @@ public class TurretBlocks extends BlockList implements ContentList { ammoUseEffect = ShootFx.shellEjectSmall; }};*/ - hail = new ArtilleryTurret("hail") {{ - ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary}; - reload = 100f; - recoil = 2f; - range = 200f; - inaccuracy = 5f; - health = 120; - }}; + hail = new ArtilleryTurret("hail"){{ + ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary}; + reload = 100f; + recoil = 2f; + range = 200f; + inaccuracy = 5f; + health = 120; + }}; - scorch = new LiquidTurret("scorch") {{ + scorch = new LiquidTurret("scorch"){{ ammoTypes = new AmmoType[]{AmmoTypes.basicFlame}; recoil = 0f; reload = 4f; shootCone = 50f; ammoUseEffect = ShootFx.shellEjectSmall; - health = 160; + health = 160; drawer = (tile, entity) -> Draw.rect(entity.target != null ? name + "-shoot" : name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); }}; - wave = new LiquidTurret("wave") {{ - ammoTypes = new AmmoType[]{AmmoTypes.water, AmmoTypes.lava, AmmoTypes.cryofluid, AmmoTypes.oil}; - size = 2; - recoil = 0f; - reload = 4f; - inaccuracy = 5f; - shootCone = 50f; - shootEffect = ShootFx.shootLiquid; - range = 70f; - health = 360; + wave = new LiquidTurret("wave"){{ + ammoTypes = new AmmoType[]{AmmoTypes.water, AmmoTypes.lava, AmmoTypes.cryofluid, AmmoTypes.oil}; + size = 2; + recoil = 0f; + reload = 4f; + inaccuracy = 5f; + shootCone = 50f; + shootEffect = ShootFx.shootLiquid; + range = 70f; + health = 360; - drawer = (tile, entity) -> { - Draw.rect(name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + drawer = (tile, entity) -> { + Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - Draw.color(entity.liquids.liquid.color); - Draw.alpha(entity.liquids.amount / liquidCapacity); - Draw.rect(name + "-liquid", tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - Draw.color(); - }; - }}; + Draw.color(entity.liquids.current().color); + Draw.alpha(entity.liquids.total() / liquidCapacity); + Draw.rect(name + "-liquid", tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + Draw.color(); + }; + }}; - lancer = new LaserTurret("lancer") {{ - range = 90f; - chargeTime = 60f; - chargeMaxDelay = 30f; - chargeEffects = 7; - shootType = AmmoTypes.lancerLaser; - recoil = 2f; - reload = 100f; - cooldown = 0.03f; - powerUsed = 20f; - powerCapacity = 60f; - shootShake = 2f; - shootEffect = ShootFx.lancerLaserShoot; - smokeEffect = ShootFx.lancerLaserShootSmoke; - chargeEffect = ShootFx.lancerLaserCharge; - chargeBeginEffect = ShootFx.lancerLaserChargeBegin; - heatColor = Color.RED; - size = 2; - health = 320; - }}; + lancer = new LaserTurret("lancer"){{ + range = 90f; + chargeTime = 60f; + chargeMaxDelay = 30f; + chargeEffects = 7; + shootType = AmmoTypes.lancerLaser; + recoil = 2f; + reload = 100f; + cooldown = 0.03f; + powerUsed = 20f; + powerCapacity = 60f; + shootShake = 2f; + shootEffect = ShootFx.lancerLaserShoot; + smokeEffect = ShootFx.lancerLaserShootSmoke; + chargeEffect = ShootFx.lancerLaserCharge; + chargeBeginEffect = ShootFx.lancerLaserChargeBegin; + heatColor = Color.RED; + size = 2; + health = 320; + }}; - arc = new LaserTurret("arc") {{ - shootType = AmmoTypes.lightning; - reload = 100f; - chargeTime = 70f; - shootShake = 1f; - chargeMaxDelay = 30f; - chargeEffects = 7; - shootEffect = ShootFx.lightningShoot; - chargeEffect = ShootFx.lightningCharge; - chargeBeginEffect = ShootFx.lancerLaserChargeBegin; - heatColor = Color.RED; - recoil = 3f; - size = 2; - }}; + arc = new LaserTurret("arc"){{ + shootType = AmmoTypes.lightning; + reload = 100f; + chargeTime = 70f; + shootShake = 1f; + chargeMaxDelay = 30f; + chargeEffects = 7; + shootEffect = ShootFx.lightningShoot; + chargeEffect = ShootFx.lightningCharge; + chargeBeginEffect = ShootFx.lancerLaserChargeBegin; + heatColor = Color.RED; + recoil = 3f; + size = 2; + }}; - swarmer = new BurstTurret("swarmer") {{ - ammoTypes = new AmmoType[]{AmmoTypes.missileExplosive, AmmoTypes.missileIncindiary/*, AmmoTypes.missileSurge*/}; - reload = 60f; - shots = 4; - burstSpacing = 5; - inaccuracy = 10f; - range = 140f; - xRand = 6f; - size = 2; - health = 380; - }}; + swarmer = new BurstTurret("swarmer"){{ + ammoTypes = new AmmoType[]{AmmoTypes.missileExplosive, AmmoTypes.missileIncindiary/*, AmmoTypes.missileSurge*/}; + reload = 60f; + shots = 4; + burstSpacing = 5; + inaccuracy = 10f; + range = 140f; + xRand = 6f; + size = 2; + health = 380; + }}; - salvo = new BurstTurret("salvo") {{ - size = 2; - range = 120f; - ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon}; - reload = 40f; - restitution = 0.03f; - ammoEjectBack = 3f; - cooldown = 0.03f; - recoil = 3f; - shootShake = 2f; - burstSpacing = 4; - shots = 3; - ammoUseEffect = ShootFx.shellEjectBig; + salvo = new BurstTurret("salvo"){{ + size = 2; + range = 120f; + ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon}; + reload = 40f; + restitution = 0.03f; + ammoEjectBack = 3f; + cooldown = 0.03f; + recoil = 3f; + shootShake = 2f; + burstSpacing = 4; + shots = 3; + ammoUseEffect = ShootFx.shellEjectBig; - drawer = (tile, entity) -> { - Draw.rect(name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - float offsetx = (int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 3f); - float offsety = -(int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 2f); + drawer = (tile, entity) -> { + Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + float offsetx = (int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 3f); + float offsety = -(int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 2f); - for (int i : Mathf.signs) { - float rot = entity.rotation + 90 * i; - Draw.rect(name + "-panel-" + Strings.dir(i), - tile.drawx() + tr2.x + Angles.trnsx(rot, offsetx, offsety), - tile.drawy() + tr2.y + Angles.trnsy(rot, -offsetx, offsety), entity.rotation - 90); - } - }; + for(int i : Mathf.signs){ + float rot = entity.rotation + 90 * i; + Draw.rect(name + "-panel-" + Strings.dir(i), + tile.drawx() + tr2.x + Angles.trnsx(rot, offsetx, offsety), + tile.drawy() + tr2.y + Angles.trnsy(rot, -offsetx, offsety), entity.rotation - 90); + } + }; - health = 360; - }}; + health = 360; + }}; - ripple = new ArtilleryTurret("ripple") {{ - ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary, AmmoTypes.artilleryExplosive, AmmoTypes.artilleryPlastic}; - size = 3; - shots = 4; - inaccuracy = 12f; - reload = 60f; - ammoEjectBack = 5f; + ripple = new ArtilleryTurret("ripple"){{ + ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary, AmmoTypes.artilleryExplosive, AmmoTypes.artilleryPlastic}; + size = 3; + shots = 4; + inaccuracy = 12f; + reload = 60f; + ammoEjectBack = 5f; ammoUseEffect = ShootFx.shellEjectBig; cooldown = 0.03f; - velocityInaccuracy = 0.2f; + velocityInaccuracy = 0.2f; restitution = 0.02f; recoil = 6f; shootShake = 2f; range = 300f; - health = 550; - }}; + health = 550; + }}; - cyclone = new ItemTurret("cyclone") {{ - ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic, AmmoTypes.flakSurge}; - size = 3; - }}; + cyclone = new ItemTurret("cyclone"){{ + ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic, AmmoTypes.flakSurge}; + size = 3; + }}; - fuse = new ItemTurret("fuse") {{ - //TODO make it use power - ammoTypes = new AmmoType[]{AmmoTypes.fuseShotgun}; - size = 3; - }}; + fuse = new ItemTurret("fuse"){{ + //TODO make it use power + ammoTypes = new AmmoType[]{AmmoTypes.fuseShotgun}; + size = 3; + }}; - spectre = new ItemTurret("spectre") {{ - ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon}; - reload = 25f; - restitution = 0.03f; - ammoUseEffect = ShootFx.shellEjectSmall; - size = 4; - }}; + spectre = new ItemTurret("spectre"){{ + ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon}; + reload = 25f; + restitution = 0.03f; + ammoUseEffect = ShootFx.shellEjectSmall; + size = 4; + }}; - meltdown = new PowerTurret("meltdown") {{ - shootType = AmmoTypes.meltdownLaser; - size = 4; - }}; - } + meltdown = new PowerTurret("meltdown"){{ + shootType = AmmoTypes.meltdownLaser; + size = 4; + }}; + } } diff --git a/core/src/io/anuke/mindustry/content/blocks/UnitBlocks.java b/core/src/io/anuke/mindustry/content/blocks/UnitBlocks.java index 397e70cba3..dc98341364 100644 --- a/core/src/io/anuke/mindustry/content/blocks/UnitBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/UnitBlocks.java @@ -7,54 +7,51 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.units.*; -public class UnitBlocks extends BlockList implements ContentList { +public class UnitBlocks extends BlockList implements ContentList{ public static Block resupplyPoint, repairPoint, droneFactory, fabricatorFactory, dropPoint, reconstructor, overdriveProjector, shieldProjector; @Override - public void load() { - droneFactory = new UnitFactory("drone-factory") {{ + public void load(){ + droneFactory = new UnitFactory("drone-factory"){{ type = UnitTypes.drone; produceTime = 800; size = 2; - requirements = new ItemStack[]{ - new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30) - }; + consumes.power(0.08f); + consumes.items(new ItemStack[]{new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30)}); }}; - fabricatorFactory = new UnitFactory("fabricator-factory") {{ + fabricatorFactory = new UnitFactory("fabricator-factory"){{ type = UnitTypes.fabricator; produceTime = 1600; size = 2; - powerUse = 0.2f; - requirements = new ItemStack[]{ - new ItemStack(Items.silicon, 70), new ItemStack(Items.lead, 80), new ItemStack(Items.titanium, 80) - }; + consumes.power(0.2f); + consumes.items(new ItemStack[]{new ItemStack(Items.silicon, 70), new ItemStack(Items.lead, 80), new ItemStack(Items.titanium, 80)}); }}; - resupplyPoint = new ResupplyPoint("resupply-point") {{ + resupplyPoint = new ResupplyPoint("resupply-point"){{ shadow = "shadow-round-1"; itemCapacity = 30; }}; - dropPoint = new DropPoint("drop-point") {{ + dropPoint = new DropPoint("drop-point"){{ shadow = "shadow-round-1"; itemCapacity = 40; }}; - repairPoint = new RepairPoint("repair-point") {{ + repairPoint = new RepairPoint("repair-point"){{ shadow = "shadow-round-1"; repairSpeed = 0.1f; }}; - reconstructor = new Reconstructor("reconstructor") {{ + reconstructor = new Reconstructor("reconstructor"){{ size = 2; }}; - overdriveProjector = new OverdriveProjector("overdrive-projector") {{ + overdriveProjector = new OverdriveProjector("overdrive-projector"){{ size = 2; }}; - shieldProjector = new ShieldProjector("shieldprojector") {{ + shieldProjector = new ShieldProjector("shieldprojector"){{ size = 2; }}; } diff --git a/core/src/io/anuke/mindustry/content/blocks/UpgradeBlocks.java b/core/src/io/anuke/mindustry/content/blocks/UpgradeBlocks.java index 7382e726fe..c66cfba208 100644 --- a/core/src/io/anuke/mindustry/content/blocks/UpgradeBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/UpgradeBlocks.java @@ -4,11 +4,11 @@ import io.anuke.mindustry.content.Mechs; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.units.MechFactory; -public class UpgradeBlocks extends BlockList { +public class UpgradeBlocks extends BlockList{ public static Block deltaFactory, tauFactory, omegaFactory, dartFactory, javelinFactory, tridentFactory, halberdFactory; @Override - public void load() { + public void load(){ deltaFactory = new MechFactory("delta-mech-factory"){{ mech = Mechs.delta; size = 2; diff --git a/core/src/io/anuke/mindustry/content/bullets/ArtilleryBullets.java b/core/src/io/anuke/mindustry/content/bullets/ArtilleryBullets.java index 0747fecae7..5898a70070 100644 --- a/core/src/io/anuke/mindustry/content/bullets/ArtilleryBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/ArtilleryBullets.java @@ -11,9 +11,9 @@ public class ArtilleryBullets extends BulletList implements ContentList{ public static BulletType carbide, plastic, plasticFrag, homing, incindiary, explosive, surge; @Override - public void load() { + public void load(){ - carbide = new ArtilleryBulletType(3f, 0, "shell") { + carbide = new ArtilleryBulletType(3f, 0, "shell"){ { hiteffect = BulletFx.flakExplosion; knockback = 0.8f; @@ -25,7 +25,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - plasticFrag = new BasicBulletType(2.5f, 6, "bullet") { + plasticFrag = new BasicBulletType(2.5f, 6, "bullet"){ { bulletWidth = 10f; bulletHeight = 12f; @@ -36,7 +36,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - plastic = new ArtilleryBulletType(3.3f, 0, "shell") { + plastic = new ArtilleryBulletType(3.3f, 0, "shell"){ { hiteffect = BulletFx.plasticExplosion; knockback = 1f; @@ -52,7 +52,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - homing = new ArtilleryBulletType(3f, 0, "shell") { + homing = new ArtilleryBulletType(3f, 0, "shell"){ { hiteffect = BulletFx.flakExplosion; knockback = 0.8f; @@ -66,7 +66,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - incindiary = new ArtilleryBulletType(3f, 0, "shell") { + incindiary = new ArtilleryBulletType(3f, 0, "shell"){ { hiteffect = BulletFx.blastExplosion; knockback = 0.8f; @@ -83,7 +83,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - explosive = new ArtilleryBulletType(2f, 0, "shell") { + explosive = new ArtilleryBulletType(2f, 0, "shell"){ { hiteffect = BulletFx.blastExplosion; knockback = 0.8f; @@ -97,7 +97,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{ } }; - surge = new ArtilleryBulletType(3f, 0, "shell") { + surge = new ArtilleryBulletType(3f, 0, "shell"){ { //TODO } diff --git a/core/src/io/anuke/mindustry/content/bullets/BulletList.java b/core/src/io/anuke/mindustry/content/bullets/BulletList.java index dac973f2e0..ba0e465799 100644 --- a/core/src/io/anuke/mindustry/content/bullets/BulletList.java +++ b/core/src/io/anuke/mindustry/content/bullets/BulletList.java @@ -5,10 +5,10 @@ import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; -public abstract class BulletList implements ContentList { +public abstract class BulletList implements ContentList{ @Override - public Array getAll() { + public Array getAll(){ return BulletType.all(); } } diff --git a/core/src/io/anuke/mindustry/content/bullets/FlakBullets.java b/core/src/io/anuke/mindustry/content/bullets/FlakBullets.java index fdcec72362..276cb76c7d 100644 --- a/core/src/io/anuke/mindustry/content/bullets/FlakBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/FlakBullets.java @@ -4,34 +4,34 @@ import io.anuke.mindustry.entities.bullet.BasicBulletType; import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.type.ContentList; -public class FlakBullets extends BulletList implements ContentList { +public class FlakBullets extends BulletList implements ContentList{ public static BulletType lead, plastic, explosive, surge; @Override - public void load() { + public void load(){ - lead = new BasicBulletType(3f, 5, "bullet") { + lead = new BasicBulletType(3f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; } }; - plastic = new BasicBulletType(3f, 5, "bullet") { + plastic = new BasicBulletType(3f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; } }; - explosive = new BasicBulletType(3f, 5, "bullet") { + explosive = new BasicBulletType(3f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; } }; - surge = new BasicBulletType(3f, 5, "bullet") { + surge = new BasicBulletType(3f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; diff --git a/core/src/io/anuke/mindustry/content/bullets/MissileBullets.java b/core/src/io/anuke/mindustry/content/bullets/MissileBullets.java index f004eac290..ceea3423f2 100644 --- a/core/src/io/anuke/mindustry/content/bullets/MissileBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/MissileBullets.java @@ -6,13 +6,13 @@ import io.anuke.mindustry.entities.bullet.MissileBulletType; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.type.ContentList; -public class MissileBullets extends BulletList implements ContentList { +public class MissileBullets extends BulletList implements ContentList{ public static BulletType explosive, incindiary, surge, javelin; @Override - public void load() { + public void load(){ - explosive = new MissileBulletType(1.8f, 10, "missile") { + explosive = new MissileBulletType(1.8f, 10, "missile"){ { bulletWidth = 8f; bulletHeight = 8f; @@ -26,7 +26,7 @@ public class MissileBullets extends BulletList implements ContentList { } }; - incindiary = new MissileBulletType(2f, 12, "missile") { + incindiary = new MissileBulletType(2f, 12, "missile"){ { frontColor = Palette.lightishOrange; backColor = Palette.lightOrange; @@ -44,14 +44,14 @@ public class MissileBullets extends BulletList implements ContentList { } }; - surge = new MissileBulletType(3f, 5, "bullet") { + surge = new MissileBulletType(3f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; } }; - javelin = new MissileBulletType(2.5f, 10, "missile") { + javelin = new MissileBulletType(2.5f, 10, "missile"){ { bulletWidth = 8f; bulletHeight = 8f; diff --git a/core/src/io/anuke/mindustry/content/bullets/StandardBullets.java b/core/src/io/anuke/mindustry/content/bullets/StandardBullets.java index 37efcda5e0..0c0939ac67 100644 --- a/core/src/io/anuke/mindustry/content/bullets/StandardBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/StandardBullets.java @@ -5,27 +5,27 @@ import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.type.ContentList; -public class StandardBullets extends BulletList implements ContentList { +public class StandardBullets extends BulletList implements ContentList{ public static BulletType tungsten, lead, carbide, thorium, homing, tracer; @Override - public void load() { + public void load(){ - tungsten = new BasicBulletType(3.2f, 10, "bullet") { + tungsten = new BasicBulletType(3.2f, 10, "bullet"){ { bulletWidth = 9f; bulletHeight = 11f; } }; - lead = new BasicBulletType(2.5f, 5, "bullet") { + lead = new BasicBulletType(2.5f, 5, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; } }; - carbide = new BasicBulletType(3.5f, 18, "bullet") { + carbide = new BasicBulletType(3.5f, 18, "bullet"){ { bulletWidth = 9f; bulletHeight = 12f; @@ -33,7 +33,7 @@ public class StandardBullets extends BulletList implements ContentList { } }; - thorium = new BasicBulletType(4f, 29, "bullet") { + thorium = new BasicBulletType(4f, 29, "bullet"){ { bulletWidth = 10f; bulletHeight = 13f; @@ -41,7 +41,7 @@ public class StandardBullets extends BulletList implements ContentList { } }; - homing = new BasicBulletType(3f, 9, "bullet") { + homing = new BasicBulletType(3f, 9, "bullet"){ { bulletWidth = 7f; bulletHeight = 9f; @@ -49,7 +49,7 @@ public class StandardBullets extends BulletList implements ContentList { } }; - tracer = new BasicBulletType(3.2f, 11, "bullet") { + tracer = new BasicBulletType(3.2f, 11, "bullet"){ { bulletWidth = 10f; bulletHeight = 12f; diff --git a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java index 3912d60949..177acacb35 100644 --- a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java @@ -29,13 +29,13 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class TurretBullets extends BulletList implements ContentList { +public class TurretBullets extends BulletList implements ContentList{ public static BulletType fireball, basicFlame, lancerLaser, fuseShot, waterShot, cryoShot, lavaShot, oilShot, lightning, driverBolt; @Override - public void load() { + public void load(){ - fireball = new BulletType(1f, 4) { + fireball = new BulletType(1f, 4){ { pierce = true; hitTiles = false; @@ -45,12 +45,12 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void init(Bullet b) { + public void init(Bullet b){ b.getVelocity().setLength(0.6f + Mathf.random(2f)); } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ //TODO add color to the bullet depending on the color of the flame it came from Draw.color(Palette.lightFlame, Palette.darkFlame, Color.GRAY, b.fin()); Fill.circle(b.x, b.y, 3f * b.fout()); @@ -58,25 +58,25 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void update(Bullet b) { - if (Mathf.chance(0.04 * Timers.delta())) { + public void update(Bullet b){ + if(Mathf.chance(0.04 * Timers.delta())){ Tile tile = world.tileWorld(b.x, b.y); - if (tile != null) { + if(tile != null){ Fire.create(tile); } } - if (Mathf.chance(0.1 * Timers.delta())) { + if(Mathf.chance(0.1 * Timers.delta())){ Effects.effect(EnvironmentFx.fireballsmoke, b.x, b.y); } - if (Mathf.chance(0.1 * Timers.delta())) { + if(Mathf.chance(0.1 * Timers.delta())){ Effects.effect(EnvironmentFx.ballfire, b.x, b.y); } } }; - basicFlame = new BulletType(2f, 5) { + basicFlame = new BulletType(2f, 5){ { hitsize = 7f; lifetime = 30f; @@ -88,11 +88,11 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ } }; - lancerLaser = new BulletType(0.001f, 110) { + lancerLaser = new BulletType(0.001f, 110){ Color[] colors = {Palette.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Palette.lancerLaser, Color.WHITE}; float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; float[] lenscales = {1f, 1.1f, 1.13f, 1.14f}; @@ -107,19 +107,19 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void init(Bullet b) { + public void init(Bullet b){ Damage.collideLine(b, b.getTeam(), hiteffect, b.x, b.y, b.angle(), length); } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ float f = Mathf.curve(b.fin(), 0f, 0.2f); float baseLen = length * f; Lines.lineAngle(b.x, b.y, b.angle(), baseLen); - for (int s = 0; s < 3; s++) { + for(int s = 0; s < 3; s++){ Draw.color(colors[s]); - for (int i = 0; i < tscales.length; i++) { + for(int i = 0; i < tscales.length; i++){ Lines.stroke(7f * b.fout() * (s == 0 ? 1.5f : s == 1 ? 1f : 0.3f) * tscales[i]); Lines.lineAngle(b.x, b.y, b.angle(), baseLen * lenscales[i]); } @@ -128,24 +128,24 @@ public class TurretBullets extends BulletList implements ContentList { } }; - fuseShot = new BulletType(0.01f, 100) { + fuseShot = new BulletType(0.01f, 100){ //TODO }; - waterShot = new LiquidBulletType(Liquids.water) { + waterShot = new LiquidBulletType(Liquids.water){ { status = StatusEffects.wet; statusIntensity = 0.5f; knockback = 0.65f; } }; - cryoShot = new LiquidBulletType(Liquids.cryofluid) { + cryoShot = new LiquidBulletType(Liquids.cryofluid){ { status = StatusEffects.freezing; statusIntensity = 0.5f; } }; - lavaShot = new LiquidBulletType(Liquids.lava) { + lavaShot = new LiquidBulletType(Liquids.lava){ { damage = 4; speed = 1.9f; @@ -154,7 +154,7 @@ public class TurretBullets extends BulletList implements ContentList { statusIntensity = 0.5f; } }; - oilShot = new LiquidBulletType(Liquids.oil) { + oilShot = new LiquidBulletType(Liquids.oil){ { speed = 2f; drag = 0.03f; @@ -162,7 +162,7 @@ public class TurretBullets extends BulletList implements ContentList { statusIntensity = 0.5f; } }; - lightning = new BulletType(0.001f, 10) { + lightning = new BulletType(0.001f, 10){ { lifetime = 1; despawneffect = Fx.none; @@ -170,16 +170,16 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ } @Override - public void init(Bullet b) { + public void init(Bullet b){ Lightning.create(b.getTeam(), hiteffect, Palette.lancerLaser, damage, b.x, b.y, b.angle(), 30); } }; - driverBolt = new BulletType(5f, 20) { + driverBolt = new BulletType(5f, 20){ { collidesTiles = false; lifetime = 200f; @@ -189,7 +189,7 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ Draw.color(Color.LIGHT_GRAY); Fill.square(b.x, b.y, 3f, b.angle()); @@ -199,7 +199,7 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void update(Bullet b) { + public void update(Bullet b){ //data MUST be an instance of DriverBulletData if(!(b.getData() instanceof DriverBulletData)){ hit(b); @@ -208,7 +208,7 @@ public class TurretBullets extends BulletList implements ContentList { float hitDst = 7f; - DriverBulletData data = (DriverBulletData)b.getData(); + DriverBulletData data = (DriverBulletData) b.getData(); //if the target is dead, just keep flying until the bullet explodes if(data.to.isDead()){ @@ -245,15 +245,15 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void despawned(Bullet b) { + public void despawned(Bullet b){ super.despawned(b); if(!(b.getData() instanceof DriverBulletData)) return; - DriverBulletData data = (DriverBulletData)b.getData(); + DriverBulletData data = (DriverBulletData) b.getData(); data.to.isRecieving = false; - for(int i = 0; i < data.items.length; i ++){ + for(int i = 0; i < data.items.length; i++){ int amountDropped = Mathf.random(0, data.items[i]); if(amountDropped > 0){ float angle = b.angle() + Mathf.range(100f); @@ -264,7 +264,7 @@ public class TurretBullets extends BulletList implements ContentList { } @Override - public void hit(Bullet b, float hitx, float hity) { + public void hit(Bullet b, float hitx, float hity){ super.hit(b, hitx, hity); despawned(b); } diff --git a/core/src/io/anuke/mindustry/content/bullets/WeaponBullets.java b/core/src/io/anuke/mindustry/content/bullets/WeaponBullets.java index d7195ee768..04997b8c68 100644 --- a/core/src/io/anuke/mindustry/content/bullets/WeaponBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/WeaponBullets.java @@ -16,12 +16,12 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class WeaponBullets extends BulletList { +public class WeaponBullets extends BulletList{ public static BulletType tungstenShotgun, bombExplosive, bombIncendiary, bombOil, shellCarbide; @Override - public void load() { - tungstenShotgun = new BasicBulletType(5f, 8, "bullet") { + public void load(){ + tungstenShotgun = new BasicBulletType(5f, 8, "bullet"){ { bulletWidth = 8f; bulletHeight = 9f; @@ -49,10 +49,10 @@ public class WeaponBullets extends BulletList { } @Override - public void hit(Bullet b, float x, float y) { + public void hit(Bullet b, float x, float y){ super.hit(b, x, y); - for (int i = 0; i < 3; i++) { + for(int i = 0; i < 3; i++){ float cx = x + Mathf.range(10f); float cy = y + Mathf.range(10f); Tile tile = world.tileWorld(cx, cy); @@ -73,17 +73,17 @@ public class WeaponBullets extends BulletList { } @Override - public void hit(Bullet b, float x, float y) { + public void hit(Bullet b, float x, float y){ super.hit(b, x, y); - for (int i = 0; i < 3; i++) { + for(int i = 0; i < 3; i++){ Tile tile = world.tileWorld(x + Mathf.range(8f), y + Mathf.range(8f)); Puddle.deposit(tile, Liquids.oil, 5f); } } }; - shellCarbide = new BasicBulletType(3.4f, 20, "bullet") { + shellCarbide = new BasicBulletType(3.4f, 20, "bullet"){ { bulletWidth = 10f; bulletHeight = 12f; diff --git a/core/src/io/anuke/mindustry/content/fx/BlockFx.java b/core/src/io/anuke/mindustry/content/fx/BlockFx.java index 14e77406c6..9260c76b0f 100644 --- a/core/src/io/anuke/mindustry/content/fx/BlockFx.java +++ b/core/src/io/anuke/mindustry/content/fx/BlockFx.java @@ -19,7 +19,7 @@ public class BlockFx extends FxList implements ContentList{ public static Effect reactorsmoke, nuclearsmoke, nuclearcloud, redgeneratespark, generatespark, fuelburn, plasticburn, pulverize, pulverizeRed, pulverizeRedder, pulverizeSmall, pulverizeMedium, producesmoke, smeltsmoke, formsmoke, blastsmoke, lava, dooropen, doorclose, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate, mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble; @Override - public void load() { + public void load(){ reactorsmoke = new Effect(17, e -> { Angles.randLenVectors(e.id, 4, e.fin() * 8f, (x, y) -> { diff --git a/core/src/io/anuke/mindustry/content/fx/BulletFx.java b/core/src/io/anuke/mindustry/content/fx/BulletFx.java index d5977c3ef9..73a53a6c70 100644 --- a/core/src/io/anuke/mindustry/content/fx/BulletFx.java +++ b/core/src/io/anuke/mindustry/content/fx/BulletFx.java @@ -10,12 +10,12 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class BulletFx extends FxList implements ContentList { +public class BulletFx extends FxList implements ContentList{ public static Effect hitBulletSmall, hitBulletBig, hitFlameSmall, hitLiquid, hitLancer, despawn, flakExplosion, blastExplosion, plasticExplosion, artilleryTrail, incendTrail, missileTrail; @Override - public void load() { + public void load(){ hitBulletSmall = new Effect(14, e -> { Draw.color(Color.WHITE, Palette.lightOrange, e.fin()); diff --git a/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java b/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java index d1eb624141..e8f3fe6b2e 100644 --- a/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java +++ b/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java @@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class EnvironmentFx extends FxList implements ContentList { +public class EnvironmentFx extends FxList implements ContentList{ public static Effect burning, fire, smoke, steam, fireballsmoke, ballfire, freezing, melting, wet, oily; @Override - public void load() { + public void load(){ burning = new Effect(35f, e -> { Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin()); diff --git a/core/src/io/anuke/mindustry/content/fx/ExplosionFx.java b/core/src/io/anuke/mindustry/content/fx/ExplosionFx.java index 78f4a7e4fa..457c2dfe32 100644 --- a/core/src/io/anuke/mindustry/content/fx/ExplosionFx.java +++ b/core/src/io/anuke/mindustry/content/fx/ExplosionFx.java @@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class ExplosionFx extends FxList implements ContentList { +public class ExplosionFx extends FxList implements ContentList{ public static Effect shockwave, bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke; @Override - public void load() { + public void load(){ shockwave = new Effect(10f, 80f, e -> { Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin()); diff --git a/core/src/io/anuke/mindustry/content/fx/Fx.java b/core/src/io/anuke/mindustry/content/fx/Fx.java index 693a412742..f76f12d233 100644 --- a/core/src/io/anuke/mindustry/content/fx/Fx.java +++ b/core/src/io/anuke/mindustry/content/fx/Fx.java @@ -11,59 +11,59 @@ import io.anuke.ucore.util.Angles; import static io.anuke.mindustry.Vars.tilesize; -public class Fx extends FxList implements ContentList { - public static Effect none, placeBlock, breakBlock, smoke, spawn, tapBlock, select; +public class Fx extends FxList implements ContentList{ + public static Effect none, placeBlock, breakBlock, smoke, spawn, tapBlock, select; - @Override - public void load() { + @Override + public void load(){ - none = new Effect(0, 0f, e -> { - }); + none = new Effect(0, 0f, e -> { + }); - placeBlock = new Effect(16, e -> { - Draw.color(Palette.accent); - Lines.stroke(3f - e.fin() * 2f); - Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); - Draw.reset(); - }); + placeBlock = new Effect(16, e -> { + Draw.color(Palette.accent); + Lines.stroke(3f - e.fin() * 2f); + Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); + Draw.reset(); + }); - tapBlock = new Effect(12, e -> { - Draw.color(Palette.accent); - Lines.stroke(3f - e.fin() * 2f); - Lines.circle(e.x, e.y, 4f + (tilesize/1.5f * e.rotation) * e.fin()); - Draw.reset(); - }); + tapBlock = new Effect(12, e -> { + Draw.color(Palette.accent); + Lines.stroke(3f - e.fin() * 2f); + Lines.circle(e.x, e.y, 4f + (tilesize / 1.5f * e.rotation) * e.fin()); + Draw.reset(); + }); - breakBlock = new Effect(12, e -> { - Draw.color(Palette.remove); - Lines.stroke(3f - e.fin() * 2f); - Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); + breakBlock = new Effect(12, e -> { + Draw.color(Palette.remove); + Lines.stroke(3f - e.fin() * 2f); + Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); - Angles.randLenVectors(e.id, 3 + (int) (e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> { - Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation)); - }); - Draw.reset(); - }); + Angles.randLenVectors(e.id, 3 + (int) (e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> { + Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation)); + }); + Draw.reset(); + }); - select = new Effect(23, e -> { - Draw.color(Palette.accent); - Lines.stroke(e.fout() * 3f); - Lines.circle(e.x, e.y, 3f + e.fin() * 14f); - Draw.reset(); - }); + select = new Effect(23, e -> { + Draw.color(Palette.accent); + Lines.stroke(e.fout() * 3f); + Lines.circle(e.x, e.y, 3f + e.fin() * 14f); + Draw.reset(); + }); - smoke = new Effect(100, e -> { - Draw.color(Color.GRAY, Palette.darkishGray, e.fin()); - float size = 7f - e.fin() * 7f; - Draw.rect("circle", e.x, e.y, size, size); - Draw.reset(); - }); + smoke = new Effect(100, e -> { + Draw.color(Color.GRAY, Palette.darkishGray, e.fin()); + float size = 7f - e.fin() * 7f; + Draw.rect("circle", e.x, e.y, size, size); + Draw.reset(); + }); - spawn = new Effect(23, e -> { - Lines.stroke(2f * e.fout()); - Draw.color(Palette.accent); - Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f); - Draw.reset(); - }); - } + spawn = new Effect(23, e -> { + Lines.stroke(2f * e.fout()); + Draw.color(Palette.accent); + Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f); + Draw.reset(); + }); + } } diff --git a/core/src/io/anuke/mindustry/content/fx/FxList.java b/core/src/io/anuke/mindustry/content/fx/FxList.java index f1fd467602..fe87cc2eb8 100644 --- a/core/src/io/anuke/mindustry/content/fx/FxList.java +++ b/core/src/io/anuke/mindustry/content/fx/FxList.java @@ -7,7 +7,7 @@ import io.anuke.mindustry.type.ContentList; public abstract class FxList implements ContentList{ @Override - public Array getAll() { + public Array getAll(){ return Array.with(); } } diff --git a/core/src/io/anuke/mindustry/content/fx/ShootFx.java b/core/src/io/anuke/mindustry/content/fx/ShootFx.java index b0a83f7f80..2e55246cc8 100644 --- a/core/src/io/anuke/mindustry/content/fx/ShootFx.java +++ b/core/src/io/anuke/mindustry/content/fx/ShootFx.java @@ -12,11 +12,11 @@ import io.anuke.ucore.graphics.Shapes; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class ShootFx extends FxList implements ContentList { +public class ShootFx extends FxList implements ContentList{ public static Effect shootSmall, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium, shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot; @Override - public void load() { + public void load(){ shootSmall = new Effect(8, e -> { Draw.color(Palette.lighterOrange, Palette.lightOrange, e.fin()); @@ -111,7 +111,7 @@ public class ShootFx extends FxList implements ContentList { shellEjectMedium = new GroundEffect(34f, 400f, e -> { Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin()); float rot = e.rotation + 90f; - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ float len = (2f + e.finpow() * 10f) * i; float lr = rot + e.fin() * 20f * i; Draw.rect("casing", @@ -122,7 +122,7 @@ public class ShootFx extends FxList implements ContentList { Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ Angles.randLenVectors(e.id, 4, 1f + e.finpow() * 11f, e.rotation + 90f * i, 20f, (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f); }); @@ -134,7 +134,7 @@ public class ShootFx extends FxList implements ContentList { shellEjectBig = new GroundEffect(22f, 400f, e -> { Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin()); float rot = e.rotation + 90f; - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ float len = (4f + e.finpow() * 8f) * i; float lr = rot + Mathf.randomSeedRange(e.id + i + 6, 20f * e.fin()) * i; Draw.rect("casing", @@ -146,7 +146,7 @@ public class ShootFx extends FxList implements ContentList { Draw.color(Color.LIGHT_GRAY); - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ Angles.randLenVectors(e.id, 4, -e.finpow() * 15f, e.rotation + 90f * i, 25f, (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 2f); }); @@ -158,7 +158,7 @@ public class ShootFx extends FxList implements ContentList { lancerLaserShoot = new Effect(21f, e -> { Draw.color(Palette.lancerLaser); - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ Shapes.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i); } diff --git a/core/src/io/anuke/mindustry/content/fx/UnitFx.java b/core/src/io/anuke/mindustry/content/fx/UnitFx.java index 3035fce5b1..69117a0237 100644 --- a/core/src/io/anuke/mindustry/content/fx/UnitFx.java +++ b/core/src/io/anuke/mindustry/content/fx/UnitFx.java @@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -public class UnitFx extends FxList implements ContentList { +public class UnitFx extends FxList implements ContentList{ public static Effect vtolHover, unitDrop, unitPickup, pickup; @Override - public void load() { + public void load(){ vtolHover = new Effect(40f, e -> { float len = e.finpow() * 10f; diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index d60fd098a3..db6a5ed7a2 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -25,76 +25,80 @@ import io.anuke.ucore.core.Effects; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.util.Log; -/**Loads all game content. - * Call load() before doing anything with content.*/ -public class ContentLoader { +/** + * Loads all game content. + * Call load() before doing anything with content. + */ +public class ContentLoader{ private static boolean loaded = false; private static ObjectSet> contentSet = new OrderedSet<>(); private static OrderedMap> contentMap = new OrderedMap<>(); private static ObjectSet> initialization = new ObjectSet<>(); private static ContentList[] content = { - //effects - new BlockFx(), - new BulletFx(), - new EnvironmentFx(), - new ExplosionFx(), - new Fx(), - new ShootFx(), - new UnitFx(), + //effects + new BlockFx(), + new BulletFx(), + new EnvironmentFx(), + new ExplosionFx(), + new Fx(), + new ShootFx(), + new UnitFx(), - //items - new Items(), + //items + new Items(), - //status effects - new StatusEffects(), + //status effects + new StatusEffects(), - //liquids - new Liquids(), + //liquids + new Liquids(), - //bullets - new ArtilleryBullets(), - new FlakBullets(), - new MissileBullets(), - new StandardBullets(), - new TurretBullets(), - new WeaponBullets(), + //bullets + new ArtilleryBullets(), + new FlakBullets(), + new MissileBullets(), + new StandardBullets(), + new TurretBullets(), + new WeaponBullets(), - //ammotypes - new AmmoTypes(), + //ammotypes + new AmmoTypes(), - //weapons - new Weapons(), + //weapons + new Weapons(), - //mechs - new Mechs(), + //mechs + new Mechs(), - //units - new UnitTypes(), + //units + new UnitTypes(), - //blocks - new Blocks(), - new DefenseBlocks(), - new DistributionBlocks(), - new ProductionBlocks(), - new TurretBlocks(), - new DebugBlocks(), - new LiquidBlocks(), - new StorageBlocks(), - new UnitBlocks(), - new PowerBlocks(), - new CraftingBlocks(), - new UpgradeBlocks(), - new OreBlocks(), + //blocks + new Blocks(), + new DefenseBlocks(), + new DistributionBlocks(), + new ProductionBlocks(), + new TurretBlocks(), + new DebugBlocks(), + new LiquidBlocks(), + new StorageBlocks(), + new UnitBlocks(), + new PowerBlocks(), + new CraftingBlocks(), + new UpgradeBlocks(), + new OreBlocks(), - //not really a content class, but this makes initialization easier - new ColorMapper(), + //not really a content class, but this makes initialization easier + new ColorMapper(), - //recipes - new Recipes(), + //recipes + new Recipes(), }; - /**Creates all content types.*/ + /** + * Creates all content types. + */ public static void load(){ if(loaded){ Log.info("Content already loaded, skipping."); @@ -103,11 +107,11 @@ public class ContentLoader { registerTypes(); - for (ContentList list : content){ + for(ContentList list : content){ list.load(); } - for (ContentList list : content){ + for(ContentList list : content){ if(list.getAll().size != 0){ String type = list.getAll().first().getContentTypeName(); @@ -134,7 +138,9 @@ public class ContentLoader { loaded = true; } - /**Initializes all content with the specified function.*/ + /** + * Initializes all content with the specified function. + */ public static void initialize(Consumer callable){ if(initialization.contains(callable)) return; @@ -155,8 +161,10 @@ public class ContentLoader { return contentMap; } - /**Registers sync IDs for all types of sync entities. - * Do not register units here!*/ + /** + * Registers sync IDs for all types of sync entities. + * Do not register units here! + */ private static void registerTypes(){ TypeTrait.registerType(Player.class, Player::new); TypeTrait.registerType(ItemDrop.class, ItemDrop::new); diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 0fd0d87a66..78ee87ed73 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -20,7 +20,6 @@ import io.anuke.mindustry.input.MobileInput; import io.anuke.mindustry.io.Map; import io.anuke.mindustry.io.Saves; import io.anuke.mindustry.net.Net; -import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.ucore.core.*; @@ -31,142 +30,146 @@ import io.anuke.ucore.util.Atlas; import static io.anuke.mindustry.Vars.*; -/**Control module. +/** + * Control module. * Handles all input, saving, keybinds and keybinds. * Should not handle any logic-critical state. - * This class is not created in the headless server.*/ + * This class is not created in the headless server. + */ public class Control extends Module{ - /**Minimum period of time between the same sound being played.*/ - private static final long minSoundPeriod = 100; + /** Minimum period of time between the same sound being played.*/ + private static final long minSoundPeriod = 100; - private boolean hiscore = false; - private boolean wasPaused = false; - private Saves saves; - private ContentDatabase db; - private InputHandler[] inputs = {}; - private ObjectMap soundMap = new ObjectMap<>(); + private boolean hiscore = false; + private boolean wasPaused = false; + private Saves saves; + private ContentDatabase db; + private InputHandler[] inputs = {}; + private ObjectMap soundMap = new ObjectMap<>(); private Throwable error; private Input gdxInput; - public Control(){ + public Control(){ - saves = new Saves(); - db = new ContentDatabase(); + saves = new Saves(); + db = new ContentDatabase(); - Inputs.useControllers(!gwt); + Inputs.useControllers(!gwt); - Gdx.input.setCatchBackKey(true); + Gdx.input.setCatchBackKey(true); - Effects.setShakeFalloff(10000f); + Effects.setShakeFalloff(10000f); - ContentLoader.initialize(Content::init); - Core.atlas = new Atlas("sprites.atlas"); - Core.atlas.setErrorRegion("error"); - ContentLoader.initialize(Content::load); + ContentLoader.initialize(Content::init); + Core.atlas = new Atlas("sprites.atlas"); + Core.atlas.setErrorRegion("error"); + ContentLoader.initialize(Content::load); - db.load(); + db.load(); - gdxInput = Gdx.input; + gdxInput = Gdx.input; - Sounds.load("shoot.mp3", "place.mp3", "explosion.mp3", "enemyshoot.mp3", - "corexplode.mp3", "break.mp3", "spawn.mp3", "flame.mp3", "die.mp3", - "respawn.mp3", "purchase.mp3", "flame2.mp3", "bigshot.mp3", "laser.mp3", "lasershot.mp3", - "ping.mp3", "tesla.mp3", "waveend.mp3", "railgun.mp3", "blast.mp3", "bang2.mp3"); + Sounds.load("shoot.mp3", "place.mp3", "explosion.mp3", "enemyshoot.mp3", + "corexplode.mp3", "break.mp3", "spawn.mp3", "flame.mp3", "die.mp3", + "respawn.mp3", "purchase.mp3", "flame2.mp3", "bigshot.mp3", "laser.mp3", "lasershot.mp3", + "ping.mp3", "tesla.mp3", "waveend.mp3", "railgun.mp3", "blast.mp3", "bang2.mp3"); - Sounds.setFalloff(9000f); - Sounds.setPlayer((sound, volume) -> { - long time = TimeUtils.millis(); - long value = soundMap.get(sound, 0L); + Sounds.setFalloff(9000f); + Sounds.setPlayer((sound, volume) -> { + long time = TimeUtils.millis(); + long value = soundMap.get(sound, 0L); - if(TimeUtils.timeSinceMillis(value) >= minSoundPeriod){ - threads.run(() -> sound.play(volume)); - soundMap.put(sound, time); - } - }); + if(TimeUtils.timeSinceMillis(value) >= minSoundPeriod){ + threads.run(() -> sound.play(volume)); + soundMap.put(sound, time); + } + }); Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3", "5.mp3", "6.mp3"); DefaultKeybinds.load(); - Settings.defaultList( - "ip", "localhost", - "port", port+"", - "color-0", Color.rgba8888(playerColors[8]), - "color-1", Color.rgba8888(playerColors[11]), - "color-2", Color.rgba8888(playerColors[13]), - "color-3", Color.rgba8888(playerColors[9]), - "name", "player", - "lastBuild", 0 - ); + Settings.defaultList( + "ip", "localhost", + "port", port + "", + "color-0", Color.rgba8888(playerColors[8]), + "color-1", Color.rgba8888(playerColors[11]), + "color-2", Color.rgba8888(playerColors[13]), + "color-3", Color.rgba8888(playerColors[9]), + "name", "player", + "lastBuild", 0 + ); - KeyBinds.load(); + KeyBinds.load(); - addPlayer(0); + addPlayer(0); - saves.load(); + saves.load(); - Events.on(StateChangeEvent.class, (from, to) -> { - if((from == State.playing && to == State.menu) || (from == State.menu && to != State.menu)){ - Timers.runTask(5f, Platform.instance::updateRPC); - } - }); + Events.on(StateChangeEvent.class, (from, to) -> { + if((from == State.playing && to == State.menu) || (from == State.menu && to != State.menu)){ + Timers.runTask(5f, Platform.instance::updateRPC); + } + }); - Events.on(PlayEvent.class, () -> { - for(Player player : players){ + Events.on(PlayEvent.class, () -> { + for(Player player : players){ player.add(); } - state.set(State.playing); - }); + state.set(State.playing); + }); - Events.on(WorldLoadGraphicsEvent.class, () -> { - if(mobile){ - Core.camera.position.set(players[0].x, players[0].y, 0); - } - }); + Events.on(WorldLoadGraphicsEvent.class, () -> { + if(mobile){ + Core.camera.position.set(players[0].x, players[0].y, 0); + } + }); - Events.on(ResetEvent.class, () -> { - for(Player player : players){ - player.reset(); + Events.on(ResetEvent.class, () -> { + for(Player player : players){ + player.reset(); } - hiscore = false; + hiscore = false; - saves.resetSave(); - }); + saves.resetSave(); + }); - Events.on(WaveEvent.class, () -> { + Events.on(WaveEvent.class, () -> { - int last = Settings.getInt("hiscore" + world.getMap().name, 0); + int last = Settings.getInt("hiscore" + world.getMap().name, 0); - if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){ - Settings.putInt("hiscore" + world.getMap().name, state.wave); - Settings.save(); - hiscore = true; - } + if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){ + Settings.putInt("hiscore" + world.getMap().name, state.wave); + Settings.save(); + hiscore = true; + } - Platform.instance.updateRPC(); - }); + Platform.instance.updateRPC(); + }); - Events.on(GameOverEvent.class, () -> { - Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y); + Events.on(GameOverEvent.class, () -> { + Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y); - //TODO game over effect - ui.restart.show(); + //TODO game over effect + ui.restart.show(); - Timers.runTask(30f, () -> state.set(State.menu)); - }); + Timers.runTask(30f, () -> state.set(State.menu)); + }); - Events.on(WorldLoadEvent.class, () -> threads.runGraphics(() -> Events.fire(WorldLoadGraphicsEvent.class))); - } + Events.on(WorldLoadEvent.class, () -> threads.runGraphics(() -> Events.fire(WorldLoadGraphicsEvent.class))); + } - public void addPlayer(int index){ - if(players.length != index + 1){ - Player[] old = players; - players = new Player[index + 1]; + public void addPlayer(int index){ + if(players.length != index + 1){ + Player[] old = players; + players = new Player[index + 1]; System.arraycopy(old, 0, players, 0, old.length); + } + if(inputs.length != index + 1){ InputHandler[] oldi = inputs; inputs = new InputHandler[index + 1]; System.arraycopy(oldi, 0, inputs, 0, oldi.length); @@ -204,8 +207,8 @@ public class Control extends Module{ } public void removePlayer(){ - players[players.length-1].remove(); - inputs[inputs.length-1].remove(); + players[players.length - 1].remove(); + inputs[inputs.length - 1].remove(); Player[] old = players; players = new Player[players.length - 1]; @@ -216,195 +219,191 @@ public class Control extends Module{ System.arraycopy(oldi, 0, inputs, 0, inputs.length); } - public ContentDatabase database() { - return db; - } - - public Input gdxInput(){ - return gdxInput; + public ContentDatabase database(){ + return db; } - public void setError(Throwable error){ - this.error = error; - } - - public Saves getSaves(){ - return saves; - } - - public InputHandler input(int index){ - return inputs[index]; - } - - public void triggerUpdateInput(){ - //Gdx.input = proxy; + public Input gdxInput(){ + return gdxInput; } - public void playMap(Map map){ - ui.loadfrag.show(); + public void setError(Throwable error){ + this.error = error; + } - Timers.run(5f, () -> - threads.run(() -> { - logic.reset(); - world.loadMap(map); - logic.play(); + public Saves getSaves(){ + return saves; + } - Gdx.app.postRunnable(ui.loadfrag::hide); - })); - } + public InputHandler input(int index){ + return inputs[index]; + } - public boolean isHighScore(){ - return hiscore; - } + public void triggerUpdateInput(){ + //Gdx.input = proxy; + } - private void checkUnlockableBlocks(){ - TileEntity entity = players[0].getClosestCore(); + public void playMap(Map map){ + ui.loadfrag.show(); - if(entity == null) return; + Timers.run(5f, () -> + threads.run(() -> { + logic.reset(); + world.loadMap(map); + logic.play(); - for (int i = 0; i < entity.items.items.length; i++) { - if(entity.items.items[i] <= 0) continue; - Item item = Item.getByID(i); - control.database().unlockContent(item); - } + Gdx.app.postRunnable(ui.loadfrag::hide); + })); + } - if(players[0].inventory.hasItem()){ - control.database().unlockContent(players[0].inventory.getItem().item); - } + public boolean isHighScore(){ + return hiscore; + } - for(int i = 0 ; i < Recipe.all().size; i ++){ - Recipe recipe = Recipe.all().get(i); - if(!recipe.debugOnly && entity.items.hasItems(recipe.requirements, 1.4f)){ - if(control.database().unlockContent(recipe)){ - ui.hudfrag.showUnlock(recipe); - } - } - } - } + private void checkUnlockableBlocks(){ + TileEntity entity = players[0].getClosestCore(); - @Override - public void dispose(){ - Platform.instance.onGameExit(); - ContentLoader.dispose(); - Net.dispose(); - ui.editor.dispose(); - inputs = new InputHandler[]{}; - players = new Player[]{}; - } + if(entity == null) return; - @Override - public void pause(){ - wasPaused = state.is(State.paused); - if(state.is(State.playing)) state.set(State.paused); - } + entity.items.forEach((item, amount) -> control.database().unlockContent(item)); - @Override - public void resume(){ - if(state.is(State.paused) && !wasPaused){ + if(players[0].inventory.hasItem()){ + control.database().unlockContent(players[0].inventory.getItem().item); + } + + for(int i = 0; i < Recipe.all().size; i++){ + Recipe recipe = Recipe.all().get(i); + if(!recipe.debugOnly && entity.items.has(recipe.requirements, 1.4f)){ + if(control.database().unlockContent(recipe)){ + ui.hudfrag.showUnlock(recipe); + } + } + } + } + + @Override + public void dispose(){ + Platform.instance.onGameExit(); + ContentLoader.dispose(); + Net.dispose(); + ui.editor.dispose(); + inputs = new InputHandler[]{}; + players = new Player[]{}; + } + + @Override + public void pause(){ + wasPaused = state.is(State.paused); + if(state.is(State.playing)) state.set(State.paused); + } + + @Override + public void resume(){ + if(state.is(State.paused) && !wasPaused){ state.set(State.playing); - } - } + } + } - @Override - public void init(){ - EntityPhysics.initPhysics(); + @Override + public void init(){ + EntityPhysics.initPhysics(); - Platform.instance.updateRPC(); + Platform.instance.updateRPC(); - if(!Settings.has("4.0-warning")){ - Settings.putBool("4.0-warning", true); + if(!Settings.has("4.0-warning")){ + Settings.putBool("4.0-warning", true); - Timers.run(5f, () -> { - FloatingDialog dialog = new FloatingDialog("[orange]WARNING![]"); - dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f); - dialog.content().add("The beta version you are about to play should be considered very unstable, and is [accent]not representative of the final 4.0 release.[]\n\n " + - "A large portion of content is still unimplemented. \nAll current art and UI is temporary, and will be re-drawn before release. " + - "\n\n[accent]Saves and maps may be corrupted without warning between updates.[] You have been warned!").wrap().width(500f); - dialog.show(); + Timers.run(5f, () -> { + FloatingDialog dialog = new FloatingDialog("[orange]WARNING![]"); + dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f); + dialog.content().add("The beta version you are about to play should be considered very unstable, and is [accent]not representative of the final 4.0 release.[]\n\n " + + "A large portion of content is still unimplemented. \nAll current art and UI is temporary, and will be re-drawn before release. " + + "\n\n[accent]Saves and maps may be corrupted without warning between updates.[] You have been warned!").wrap().width(500f); + dialog.show(); - }); - } + }); + } - if(!Settings.has("4.0-no-sound")){ - Settings.putBool("4.0-no-sound", true); + if(!Settings.has("4.0-no-sound")){ + Settings.putBool("4.0-no-sound", true); - Timers.run(4f, () -> { - FloatingDialog dialog = new FloatingDialog("[orange]Attention![]"); - dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f); - dialog.content().add("You might have noticed that 4.0 does not have any sound.\nThis is [orange]intentional![] Sound will be added in a later update.\n\n[LIGHT_GRAY](now stop reporting this as a bug)").wrap().width(500f); - dialog.show(); + Timers.run(4f, () -> { + FloatingDialog dialog = new FloatingDialog("[orange]Attention![]"); + dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f); + dialog.content().add("You might have noticed that 4.0 does not have any sound.\nThis is [orange]intentional![] Sound will be added in a later update.\n\n[LIGHT_GRAY](now stop reporting this as a bug)").wrap().width(500f); + dialog.show(); - }); - } - } + }); + } + } - /**Called from main logic thread.*/ - public void runUpdateLogic(){ - if(!state.is(State.menu)) { - renderer.minimap().updateUnitArray(); - } - } + /** Called from main logic thread.*/ + public void runUpdateLogic(){ + if(!state.is(State.menu)){ + renderer.minimap().updateUnitArray(); + } + } - @Override - public void update(){ + @Override + public void update(){ - if(error != null){ - throw new RuntimeException(error); - } + if(error != null){ + throw new RuntimeException(error); + } if(Inputs.keyTap("console")){ - console = !console; - } + console = !console; + } saves.update(); - triggerUpdateInput(); + triggerUpdateInput(); - for(InputHandler inputHandler : inputs){ - inputHandler.updateController(); - } + for(InputHandler inputHandler : inputs){ + inputHandler.updateController(); + } - if(!state.is(State.menu)){ - for(InputHandler input : inputs){ - input.update(); + if(!state.is(State.menu)){ + for(InputHandler input : inputs){ + input.update(); } //check unlocks every 2 seconds - if(!state.mode.infiniteResources && Timers.get("timerCheckUnlock", 120)){ - checkUnlockableBlocks(); + if(!state.mode.infiniteResources && Timers.get("timerCheckUnlock", 120)){ + checkUnlockableBlocks(); - //save if the db changed, but don't save unlocks - if(db.isDirty() && !debug){ - db.save(); - } - } + //save if the db changed, but don't save unlocks + if(db.isDirty() && !debug){ + db.save(); + } + } - if(Inputs.keyTap("pause") && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){ + if(Inputs.keyTap("pause") && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){ state.set(state.is(State.playing) ? State.paused : State.playing); - } + } - if(Inputs.keyTap("menu")){ - if(state.is(State.paused)){ - ui.paused.hide(); + if(Inputs.keyTap("menu")){ + if(state.is(State.paused)){ + ui.paused.hide(); state.set(State.playing); - }else if (!ui.restart.isShown()){ - if(ui.chatfrag.chatOpen()) { - ui.chatfrag.hide(); - }else{ - ui.paused.show(); + }else if(!ui.restart.isShown()){ + if(ui.chatfrag.chatOpen()){ + ui.chatfrag.hide(); + }else{ + ui.paused.show(); state.set(State.paused); - } - } - } + } + } + } - if(!state.is(State.paused) || Net.active()){ - Entities.update(effectGroup); - Entities.update(groundEffectGroup); - } - }else{ - if(!state.is(State.paused) || Net.active()){ - Timers.update(); - } - } - } + if(!state.is(State.paused) || Net.active()){ + Entities.update(effectGroup); + Entities.update(groundEffectGroup); + } + }else{ + if(!state.is(State.paused) || Net.active()){ + Timers.update(); + } + } + } } diff --git a/core/src/io/anuke/mindustry/core/GameState.java b/core/src/io/anuke/mindustry/core/GameState.java index b368a9867e..92eee9a4d3 100644 --- a/core/src/io/anuke/mindustry/core/GameState.java +++ b/core/src/io/anuke/mindustry/core/GameState.java @@ -8,31 +8,30 @@ import io.anuke.mindustry.game.TeamInfo; import io.anuke.ucore.core.Events; public class GameState{ - private State state = State.menu; + public int wave = 1; + public float wavetime; + public boolean gameOver = false; + public GameMode mode = GameMode.waves; + public Difficulty difficulty = Difficulty.normal; + public boolean friendlyFire; + public WaveSpawner spawner = new WaveSpawner(); + public TeamInfo teams = new TeamInfo(); + private State state = State.menu; - public int wave = 1; - public float wavetime; - public boolean gameOver = false; - public GameMode mode = GameMode.waves; - public Difficulty difficulty = Difficulty.normal; - public boolean friendlyFire; - public WaveSpawner spawner = new WaveSpawner(); - public TeamInfo teams = new TeamInfo(); - - public void set(State astate){ - Events.fire(StateChangeEvent.class, state, astate); - state = astate; - } - - public boolean is(State astate){ - return state == astate; - } + public void set(State astate){ + Events.fire(StateChangeEvent.class, state, astate); + state = astate; + } - public State getState(){ - return state; - } - - public enum State{ - paused, playing, menu - } + public boolean is(State astate){ + return state == astate; + } + + public State getState(){ + return state; + } + + public enum State{ + paused, playing, menu + } } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index b137d380f0..2e07b0a2e6 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -24,13 +24,15 @@ import io.anuke.ucore.modules.Module; import static io.anuke.mindustry.Vars.*; -/**Logic module. +/** + * Logic module. * Handles all logic for entities and waves. * Handles game state events. * Does not store any game state itself. - * - * This class should not call any outside methods to change state of modules, but instead fire events.*/ -public class Logic extends Module { + *

+ * This class should not call any outside methods to change state of modules, but instead fire events. + */ +public class Logic extends Module{ public boolean doUpdate = true; public Logic(){ @@ -49,17 +51,17 @@ public class Logic extends Module { //fill inventory with items for debugging - for (TeamData team : state.teams.getTeams()) { - for (Tile tile : team.cores) { - if(debug) { - for (Item item : Item.all()) { - if (item.type == ItemType.material) { - tile.entity.items.addItem(item, 1000); + for(TeamData team : state.teams.getTeams()){ + for(Tile tile : team.cores){ + if(debug){ + for(Item item : Item.all()){ + if(item.type == ItemType.material){ + tile.entity.items.add(item, 1000); } } }else{ - tile.entity.items.addItem(Items.tungsten, 50); - tile.entity.items.addItem(Items.lead, 20); + tile.entity.items.add(Items.tungsten, 50); + tile.entity.items.add(Items.lead, 20); } } } @@ -85,7 +87,7 @@ public class Logic extends Module { public void runWave(){ state.spawner.spawnEnemies(); - state.wave ++; + state.wave++; state.wavetime = wavespace * state.difficulty.timeScaling; Events.fire(WaveEvent.class); @@ -137,7 +139,8 @@ public class Logic extends Module { runWave(); } - if(!Entities.defaultGroup().isEmpty()) throw new RuntimeException("Do not add anything to the default group!"); + if(!Entities.defaultGroup().isEmpty()) + throw new RuntimeException("Do not add anything to the default group!"); Entities.update(bulletGroup); for(EntityGroup group : unitGroups){ @@ -158,13 +161,6 @@ public class Logic extends Module { for(EntityGroup group : unitGroups){ if(!group.isEmpty()){ EntityPhysics.collideGroups(bulletGroup, group); - - /* - for(EntityGroup other : unitGroups){ - if(!other.isEmpty()){ - EntityPhysics.collideGroups(group, other); - } - }*/ } } diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index cee76a9eae..4ba984c6d3 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.core; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Base64Coder; import com.badlogic.gdx.utils.IntSet; @@ -35,38 +36,64 @@ import java.util.Random; import static io.anuke.mindustry.Vars.*; -public class NetClient extends Module { - private final static float dataTimeout = 60*18; +public class NetClient extends Module{ + private final static float dataTimeout = 60 * 18; private final static float playerSyncTime = 2; private Timer timer = new Timer(5); - /**Whether the client is currently connecting.*/ + /** + * Whether the client is currently connecting. + */ private boolean connecting = false; - /**If true, no message will be shown on disconnect.*/ + /** + * If true, no message will be shown on disconnect. + */ private boolean quiet = false; - /**Counter for data timeout.*/ + /** + * Counter for data timeout. + */ private float timeoutTime = 0f; - /**Last sent client snapshot ID.*/ + /** + * Last sent client snapshot ID. + */ private int lastSent; - /**Last snapshot ID recieved.*/ + /** + * Last snapshot ID recieved. + */ private int lastSnapshotBaseID = -1; - /**Last snapshot recieved.*/ + /** + * Last snapshot recieved. + */ private byte[] lastSnapshotBase; - /**Current snapshot that is being built from chinks.*/ + /** + * Current snapshot that is being built from chinks. + */ private byte[] currentSnapshot; - /**Array of recieved chunk statuses.*/ + /** + * Array of recieved chunk statuses. + */ private boolean[] recievedChunks; - /**Counter of how many chunks have been recieved.*/ + /** + * Counter of how many chunks have been recieved. + */ private int recievedChunkCounter; - /**ID of snapshot that is currently being constructed.*/ + /** + * ID of snapshot that is currently being constructed. + */ private int currentSnapshotID = -1; - /**Decoder for uncompressing snapshots.*/ + /** + * Decoder for uncompressing snapshots. + */ private DEZDecoder decoder = new DEZDecoder(); - /**List of entities that were removed, and need not be added while syncing.*/ + /** + * List of entities that were removed, and need not be added while syncing. + */ private IntSet removed = new IntSet(); - /**Byte stream for reading in snapshots.*/ + /** + * Byte stream for reading in snapshots. + */ private ReusableByteArrayInputStream byteStream = new ReusableByteArrayInputStream(); private DataInputStream dataStream = new DataInputStream(byteStream); @@ -119,7 +146,7 @@ public class NetClient extends Module { }); Net.handleClient(Disconnect.class, packet -> { - if (quiet) return; + if(quiet) return; Timers.runTask(3f, ui.loadfrag::hide); @@ -144,6 +171,166 @@ public class NetClient extends Module { }); } + @Remote(variants = Variant.one, priority = PacketPriority.high) + public static void onKick(KickReason reason){ + netClient.disconnectQuietly(); + state.set(State.menu); + if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name()); + ui.loadfrag.hide(); + } + + @Remote(variants = Variant.one) + public static void onPositionSet(float x, float y){ + players[0].x = x; + players[0].y = y; + } + + @Remote(variants = Variant.one) + public static void onTraceInfo(TraceInfo info){ + Player player = playerGroup.getByID(info.playerid); + ui.traces.show(player, info); + } + + @Remote + public static void onPlayerDisconnect(int playerid){ + playerGroup.removeByID(playerid); + } + + @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) + public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, int totalLength, int base){ + if(NetServer.showSnapshotSize) + Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID); + + //skip snapshot IDs that have already been recieved OR snapshots that are too far in front + if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){ + if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT"); + return; + } + + try{ + byte[] snapshot; + + //total length exceeds that needed to hold one snapshot, therefore, it is split into chunks + if(totalLength > NetServer.maxSnapshotSize){ + //total amount of chunks to recieve + int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize); + + //reset status when a new snapshot sending begins + if(netClient.currentSnapshotID != snapshotID){ + netClient.currentSnapshotID = snapshotID; + netClient.currentSnapshot = new byte[totalLength]; + netClient.recievedChunkCounter = 0; + netClient.recievedChunks = new boolean[totalChunks]; + } + + //if this chunk hasn't been recieved yet... + if(!netClient.recievedChunks[chunkID]){ + netClient.recievedChunks[chunkID] = true; + netClient.recievedChunkCounter++; //update recieved status + //copy the recieved bytes into the holding array + System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize, + Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize)); + } + + //when all chunks have been recieved, begin + if(netClient.recievedChunkCounter >= totalChunks){ + snapshot = netClient.currentSnapshot; + }else{ + return; + } + }else{ + snapshot = chunk; + } + + if(NetServer.showSnapshotSize) + Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length); + + byte[] result; + int length; + if(base == -1){ //fresh snapshot + result = snapshot; + length = snapshot.length; + netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length); + }else{ //otherwise, last snapshot must not be null, decode it + if(NetServer.showSnapshotSize) + Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length); + netClient.decoder.init(netClient.lastSnapshotBase, snapshot); + result = netClient.decoder.decode(); + length = netClient.decoder.getDecodedLength(); + //set last snapshot to a copy to prevent issues + netClient.lastSnapshotBase = Arrays.copyOf(result, length); + } + + netClient.lastSnapshotBaseID = snapshotID; + + //set stream bytes to begin snapshot reaeding + netClient.byteStream.setBytes(result, 0, length); + + //get data input for reading from the stream + DataInputStream input = netClient.dataStream; + + //read wave info + state.wavetime = input.readFloat(); + state.wave = input.readInt(); + + byte cores = input.readByte(); + for(int i = 0; i < cores; i++){ + int pos = input.readInt(); + world.tile(pos).entity.items.read(input); + } + + long timestamp = input.readLong(); + + byte totalGroups = input.readByte(); + //for each group... + for(int i = 0; i < totalGroups; i++){ + //read group info + byte groupID = input.readByte(); + short amount = input.readShort(); + + EntityGroup group = Entities.getGroup(groupID); + + //go through each entity + for(int j = 0; j < amount; j++){ + int position = netClient.byteStream.position(); //save position to check read/write correctness + int id = input.readInt(); + byte typeID = input.readByte(); + + SyncTrait entity = (SyncTrait) group.getByID(id); + boolean add = false; + + //entity must not be added yet, so create it + if(entity == null){ + entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier + entity.resetID(id); + if(!netClient.isEntityUsed(entity.getID())){ + add = true; + } + } + + //read the entity + entity.read(input, timestamp); + + byte readLength = input.readByte(); + if(netClient.byteStream.position() - position - 1 != readLength){ + throw new RuntimeException("Error reading entity of type '" + group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1) + "]"); + } + + if(add){ + entity.add(); + netClient.addRemovedEntity(entity.getID()); + } + } + } + + //confirm that snapshot has been recieved + netClient.lastSnapshotBaseID = snapshotID; + + }catch(Exception e){ + throw new RuntimeException(e); + } + } + @Override public void update(){ if(!Net.client()) return; @@ -175,7 +362,7 @@ public class NetClient extends Module { ui.loadfrag.hide(); ui.join.hide(); Net.setClientLoaded(true); - Call.connectConfirm(); + Gdx.app.postRunnable(Call::connectConfirm); Timers.runTask(40f, Platform.instance::updateRPC); } @@ -223,161 +410,4 @@ public class NetClient extends Module { return result; } } - - @Remote(variants = Variant.one, priority = PacketPriority.high) - public static void onKick(KickReason reason){ - netClient.disconnectQuietly(); - state.set(State.menu); - if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name()); - ui.loadfrag.hide(); - } - - @Remote(variants = Variant.one) - public static void onPositionSet(float x, float y){ - players[0].x = x; - players[0].y = y; - } - - @Remote(variants = Variant.one) - public static void onTraceInfo(TraceInfo info){ - Player player = playerGroup.getByID(info.playerid); - ui.traces.show(player, info); - } - - @Remote - public static void onPlayerDisconnect(int playerid){ - playerGroup.removeByID(playerid); - } - - @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) - public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, short totalLength, int base){ - if(NetServer.showSnapshotSize) Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID); - - //skip snapshot IDs that have already been recieved OR snapshots that are too far in front - if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){ - if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT"); - return; - } - - try { - byte[] snapshot; - - //total length exceeds that needed to hold one snapshot, therefore, it is split into chunks - if(totalLength > NetServer.maxSnapshotSize) { - //total amount of chunks to recieve - int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize); - - //reset status when a new snapshot sending begins - if (netClient.currentSnapshotID != snapshotID) { - netClient.currentSnapshotID = snapshotID; - netClient.currentSnapshot = new byte[totalLength]; - netClient.recievedChunkCounter = 0; - netClient.recievedChunks = new boolean[totalChunks]; - } - - //if this chunk hasn't been recieved yet... - if (!netClient.recievedChunks[chunkID]) { - netClient.recievedChunks[chunkID] = true; - netClient.recievedChunkCounter ++; //update recieved status - //copy the recieved bytes into the holding array - System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize, - Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize)); - } - - //when all chunks have been recieved, begin - if(netClient.recievedChunkCounter >= totalChunks){ - snapshot = netClient.currentSnapshot; - }else{ - return; - } - }else{ - snapshot = chunk; - } - - if(NetServer.showSnapshotSize) Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length); - - byte[] result; - int length; - if (base == -1) { //fresh snapshot - result = snapshot; - length = snapshot.length; - netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length); - } else { //otherwise, last snapshot must not be null, decode it - if(NetServer.showSnapshotSize) Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length); - netClient.decoder.init(netClient.lastSnapshotBase, snapshot); - result = netClient.decoder.decode(); - length = netClient.decoder.getDecodedLength(); - //set last snapshot to a copy to prevent issues - netClient.lastSnapshotBase = Arrays.copyOf(result, length); - } - - netClient.lastSnapshotBaseID = snapshotID; - - //set stream bytes to begin snapshot reaeding - netClient.byteStream.setBytes(result, 0, length); - - //get data input for reading from the stream - DataInputStream input = netClient.dataStream; - - //read wave info - state.wavetime = input.readFloat(); - state.wave = input.readInt(); - - byte cores = input.readByte(); - for (int i = 0; i < cores; i++) { - int pos = input.readInt(); - world.tile(pos).entity.items.read(input); - } - - long timestamp = input.readLong(); - - byte totalGroups = input.readByte(); - //for each group... - for (int i = 0; i < totalGroups; i++) { - //read group info - byte groupID = input.readByte(); - short amount = input.readShort(); - - EntityGroup group = Entities.getGroup(groupID); - - //go through each entity - for (int j = 0; j < amount; j++) { - int position = netClient.byteStream.position(); //save position to check read/write correctness - int id = input.readInt(); - byte typeID = input.readByte(); - - SyncTrait entity = (SyncTrait) group.getByID(id); - boolean add = false; - - //entity must not be added yet, so create it - if(entity == null){ - entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier - entity.resetID(id); - if(!netClient.isEntityUsed(entity.getID())){ - add = true; - } - } - - //read the entity - entity.read(input, timestamp); - - byte readLength = input.readByte(); - if(netClient.byteStream.position() - position - 1 != readLength){ - throw new RuntimeException("Error reading entity of type '"+ group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1)+ "]"); - } - - if(add){ - entity.add(); - netClient.addRemovedEntity(entity.getID()); - } - } - } - - //confirm that snapshot has been recieved - netClient.lastSnapshotBaseID = snapshotID; - - }catch (Exception e){ - throw new RuntimeException(e); - } - } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index c8659d38f6..fa2c5ac999 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -45,20 +45,30 @@ public class NetServer extends Module{ private final static byte[] reusableSnapArray = new byte[maxSnapshotSize]; private final static float serverSyncTime = 4, kickDuration = 30 * 1000; private final static Vector2 vector = new Vector2(); - /**If a play goes away of their server-side coordinates by this distance, they get teleported back.*/ + /** + * If a play goes away of their server-side coordinates by this distance, they get teleported back. + */ private final static float correctDist = 16f; public final Administration admins = new Administration(); - /**Maps connection IDs to players.*/ + /** + * Maps connection IDs to players. + */ private IntMap connections = new IntMap<>(); private boolean closing = false; - /**Stream for writing player sync data to.*/ + /** + * Stream for writing player sync data to. + */ private CountableByteArrayOutputStream syncStream = new CountableByteArrayOutputStream(); - /**Data stream for writing player sync data to.*/ + /** + * Data stream for writing player sync data to. + */ private DataOutputStream dataStream = new DataOutputStream(syncStream); - /**Encoder for computing snapshot deltas.*/ + /** + * Encoder for computing snapshot deltas. + */ private DEZEncoder encoder = new DEZEncoder(); public NetServer(){ @@ -105,14 +115,14 @@ public class NetServer extends Module{ boolean preventDuplicates = headless; - if(preventDuplicates) { - for (Player player : playerGroup.all()) { - if (player.name.equalsIgnoreCase(packet.name)) { + if(preventDuplicates){ + for(Player player : playerGroup.all()){ + if(player.name.equalsIgnoreCase(packet.name)){ kick(id, KickReason.nameInUse); return; } - if (player.uuid.equals(packet.uuid)) { + if(player.uuid.equals(packet.uuid)){ kick(id, KickReason.idInUse); return; } @@ -181,7 +191,7 @@ public class NetServer extends Module{ long elapsed = TimeUtils.timeSinceMillis(connection.lastRecievedClientTime); - float maxSpeed = (packet.boosting && !player.mech.flying ? player.mech.boostSpeed : player.mech.speed)*2.5f; + float maxSpeed = (packet.boosting && !player.mech.flying ? player.mech.boostSpeed : player.mech.speed) * 2.5f; //extra 1.1x multiplicaton is added just in case float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f; @@ -238,6 +248,86 @@ public class NetServer extends Module{ }); } + /** + * Sends a raw byte[] snapshot to a client, splitting up into chunks when needed. + */ + private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){ + if(bytes.length < maxSnapshotSize){ + Call.onSnapshot(userid, bytes, snapshotID, (short) 0, bytes.length, base); + }else{ + int remaining = bytes.length; + int offset = 0; + int chunkid = 0; + while(remaining > 0){ + int used = Math.min(remaining, maxSnapshotSize); + byte[] toSend; + //re-use sent byte arrays when possible + if(used == maxSnapshotSize){ + toSend = reusableSnapArray; + System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset); + }else{ + toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length)); + } + Call.onSnapshot(userid, toSend, snapshotID, (short) chunkid, bytes.length, base); + + remaining -= used; + offset += used; + chunkid++; + } + } + } + + public static void onDisconnect(Player player){ + Call.sendMessage("[accent]" + player.name + " has disconnected."); + Call.onPlayerDisconnect(player.id); + player.remove(); + netServer.connections.remove(player.con.id); + } + + @Remote(targets = Loc.client, called = Loc.server) + public static void onAdminRequest(Player player, Player other, AdminAction action){ + + if(!player.isAdmin){ + Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.", + player.name, player.con.address); + return; + } + + if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself + Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name); + return; + } + + if(action == AdminAction.wave){ + //no verification is done, so admins can hypothetically spam waves + //not a real issue, because server owners may want to do just that + state.wavetime = 0f; + }else if(action == AdminAction.ban){ + netServer.admins.banPlayerIP(other.con.address); + netServer.kick(other.con.id, KickReason.banned); + Log.info("&lc{0} has banned {1}.", player.name, other.name); + }else if(action == AdminAction.kick){ + netServer.kick(other.con.id, KickReason.kick); + Log.info("&lc{0} has kicked {1}.", player.name, other.name); + }else if(action == AdminAction.trace){ + //TODO + if(player.con != null){ + Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid)); + }else{ + NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid)); + } + Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name); + } + } + + @Remote(targets = Loc.client) + public static void connectConfirm(Player player){ + player.add(); + player.con.hasConnected = true; + Call.sendMessage("[accent]" + player.name + " has connected."); + Log.info("&y{0} has connected.", player.name); + } + public void update(){ if(!headless && !closing && Net.server() && state.is(State.menu)){ closing = true; @@ -270,7 +360,7 @@ public class NetServer extends Module{ if((reason == KickReason.kick || reason == KickReason.banned) && admins.getTraceByID(getUUID(con.id)).uuid != null){ PlayerInfo info = admins.getInfo(admins.getTraceByID(getUUID(con.id)).uuid); - info.timesKicked ++; + info.timesKicked++; info.lastKicked = TimeUtils.millis(); } @@ -288,7 +378,7 @@ public class NetServer extends Module{ String fixName(String name){ - for(int i = 0; i < name.length(); i ++){ + for(int i = 0; i < name.length(); i++){ if(name.charAt(i) == '[' && i != name.length() - 1 && name.charAt(i + 1) != '[' && (i == 0 || name.charAt(i - 1) != '[')){ String prev = name.substring(0, i); String next = name.substring(i); @@ -303,7 +393,7 @@ public class NetServer extends Module{ String checkColor(String str){ - for(int i = 1; i < str.length(); i ++){ + for(int i = 1; i < str.length(); i++){ if(str.charAt(i) == ']'){ String color = str.substring(1, i); @@ -318,7 +408,7 @@ public class NetServer extends Module{ if(result.a <= 0.8f){ return str.substring(i + 1); } - }catch (Exception e){ + }catch(Exception e){ return str; } } @@ -328,10 +418,10 @@ public class NetServer extends Module{ } void sync(){ - try { + try{ //iterate through each player - for (Player player : connections.values()) { + for(Player player : connections.values()){ NetConnection connection = player.con; if(!connection.isConnected()){ @@ -344,7 +434,8 @@ public class NetServer extends Module{ //if the player hasn't acknowledged that it has recieved the packet, send the same thing again if(connection.currentBaseID < connection.lastSentSnapshotID){ - if(showSnapshotSize) Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length); + if(showSnapshotSize) + Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length); sendSplitSnapshot(connection.id, connection.lastSentSnapshot, connection.lastSentSnapshotID, connection.lastSentBase); return; } @@ -371,17 +462,17 @@ public class NetServer extends Module{ int totalGroups = 0; - for (EntityGroup group : Entities.getAllGroups()) { - if (!group.isEmpty() && (group.all().get(0) instanceof SyncTrait)) totalGroups ++; + for(EntityGroup group : Entities.getAllGroups()){ + if(!group.isEmpty() && (group.all().get(0) instanceof SyncTrait)) totalGroups++; } //write total amount of serializable groups dataStream.writeByte(totalGroups); //check for syncable groups - for (EntityGroup group : Entities.getAllGroups()) { + for(EntityGroup group : Entities.getAllGroups()){ //TODO range-check sync positions to optimize? - if (group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue; + if(group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue; //make sure mapping is enabled for this group if(!group.mappingEnabled()){ @@ -391,8 +482,8 @@ public class NetServer extends Module{ int amount = 0; for(Entity entity : group.all()){ - if(((SyncTrait)entity).isSyncing()){ - amount ++; + if(((SyncTrait) entity).isSyncing()){ + amount++; } } @@ -401,15 +492,16 @@ public class NetServer extends Module{ dataStream.writeShort(amount); for(Entity entity : group.all()){ - if(!((SyncTrait)entity).isSyncing()) continue; + if(!((SyncTrait) entity).isSyncing()) continue; int position = syncStream.position(); //write all entities now dataStream.writeInt(entity.getID()); //write id - dataStream.writeByte(((SyncTrait)entity).getTypeID()); //write type ID - ((SyncTrait)entity).write(dataStream); //write entity + dataStream.writeByte(((SyncTrait) entity).getTypeID()); //write type ID + ((SyncTrait) entity).write(dataStream); //write entity int length = syncStream.position() - position; //length must always be less than 127 bytes - if(length > 127) throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!"); + if(length > 127) + throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!"); dataStream.writeByte(length); } } @@ -433,7 +525,8 @@ public class NetServer extends Module{ //send diff, otherwise byte[] diff = ByteDeltaEncoder.toDiff(new ByteMatcherHash(connection.currentBaseSnapshot, bytes), encoder); - if(showSnapshotSize) Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length); + if(showSnapshotSize) + Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length); sendSplitSnapshot(connection.id, diff, connection.currentBaseID + 1, connection.currentBaseID); connection.lastSentSnapshot = diff; connection.lastSentSnapshotID = connection.currentBaseID + 1; @@ -441,88 +534,8 @@ public class NetServer extends Module{ } } - }catch (IOException e){ + }catch(IOException e){ e.printStackTrace(); } } - - /**Sends a raw byte[] snapshot to a client, splitting up into chunks when needed.*/ - private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){ - if(bytes.length < maxSnapshotSize){ - Call.onSnapshot(userid, bytes, snapshotID, (short)0, (short)bytes.length, base); - }else{ - int remaining = bytes.length; - int offset = 0; - int chunkid = 0; - while(remaining > 0){ - int used = Math.min(remaining, maxSnapshotSize); - byte[] toSend; - //re-use sent byte arrays when possible - if(used == maxSnapshotSize){ - toSend = reusableSnapArray; - System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset); - }else { - toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length)); - } - Call.onSnapshot(userid, toSend, snapshotID, (short)chunkid, (short)bytes.length, base); - - remaining -= used; - offset += used; - chunkid ++; - } - } - } - - public static void onDisconnect(Player player){ - Call.sendMessage("[accent]" + player.name + " has disconnected."); - Call.onPlayerDisconnect(player.id); - player.remove(); - netServer.connections.remove(player.con.id); - } - - @Remote(targets = Loc.client, called = Loc.server) - public static void onAdminRequest(Player player, Player other, AdminAction action){ - - if(!player.isAdmin){ - Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.", - player.name, player.con.address); - return; - } - - if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself - Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name); - return; - } - - String ip = player.con.address; - - if(action == AdminAction.wave) { - //no verification is done, so admins can hypothetically spam waves - //not a real issue, because server owners may want to do just that - state.wavetime = 0f; - }else if(action == AdminAction.ban){ - netServer.admins.banPlayerIP(ip); - netServer.kick(other.con.id, KickReason.banned); - Log.info("&lc{0} has banned {1}.", player.name, other.name); - }else if(action == AdminAction.kick){ - netServer.kick(other.con.id, KickReason.kick); - Log.info("&lc{0} has kicked {1}.", player.name, other.name); - }else if(action == AdminAction.trace){ - //TODO - if(player.con != null) { - Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid)); - }else{ - NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid)); - } - Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name); - } - } - - @Remote(targets = Loc.client) - public static void connectConfirm(Player player){ - player.add(); - player.con.hasConnected = true; - Call.sendMessage("[accent]" + player.name + " has connected."); - Log.info("&y{0} has connected.", player.name); - } } diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index d9e87dcd44..7462ba3eb2 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -4,8 +4,6 @@ import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Base64Coder; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.ucore.core.Settings; -import io.anuke.ucore.entities.EntityGroup; -import io.anuke.ucore.entities.trait.Entity; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.scene.ui.TextField; @@ -13,63 +11,129 @@ import java.util.Date; import java.util.Locale; import java.util.Random; -public abstract class Platform { - /**Each separate game platform should set this instance to their own implementation.*/ - public static Platform instance = new Platform() {}; +public abstract class Platform{ + /** + * Each separate game platform should set this instance to their own implementation. + */ + public static Platform instance = new Platform(){ + }; - /**Format the date using the default date formatter.*/ - public String format(Date date){return "invalid";} - /**Format a number by adding in commas or periods where needed.*/ - public String format(int number){return "invalid";} - /**Show a native error dialog.*/ - public void showError(String text){} - /**Add a text input dialog that should show up after the field is tapped.*/ - public void addDialog(TextField field){ - addDialog(field, 16); - } - /**See addDialog().*/ - public void addDialog(TextField field, int maxLength){} - /**Update discord RPC.*/ - public void updateRPC(){} - /**Called when the game is exited.*/ - public void onGameExit(){} - /**Open donation dialog. Currently android only.*/ - public void openDonations(){} - /**Whether donating is supported.*/ - public boolean canDonate(){ - return false; - } - /**Whether discord RPC is supported.*/ - public boolean hasDiscord(){return true;} - /**Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().*/ - public String getLocaleName(Locale locale){ - return locale.toString(); - } - /**Whether joining games is supported.*/ - public boolean canJoinGame(){ - return true; - } - /**Whether debug mode is enabled.*/ - public boolean isDebug(){return false;} - /**Must be a base64 string 8 bytes in length.*/ - public String getUUID(){ - String uuid = Settings.getString("uuid", ""); - if(uuid.isEmpty()){ - byte[] result = new byte[8]; - new Random().nextBytes(result); - uuid = new String(Base64Coder.encode(result)); - Settings.putString("uuid", uuid); - Settings.save(); - return uuid; - } - return uuid; - } - /**Only used for iOS or android: open the share menu for a map or save.*/ - public void shareFile(FileHandle file){} - /**Download a file. Only used on GWT backend.*/ - public void downloadFile(String name, byte[] bytes){} + /** + * Format the date using the default date formatter. + */ + public String format(Date date){ + return "invalid"; + } - /**Show a file chooser. Desktop only. + /** + * Format a number by adding in commas or periods where needed. + */ + public String format(int number){ + return "invalid"; + } + + /** + * Show a native error dialog. + */ + public void showError(String text){ + } + + /** + * Add a text input dialog that should show up after the field is tapped. + */ + public void addDialog(TextField field){ + addDialog(field, 16); + } + + /** + * See addDialog(). + */ + public void addDialog(TextField field, int maxLength){ + } + + /** + * Update discord RPC. + */ + public void updateRPC(){ + } + + /** + * Called when the game is exited. + */ + public void onGameExit(){ + } + + /** + * Open donation dialog. Currently android only. + */ + public void openDonations(){ + } + + /** + * Whether donating is supported. + */ + public boolean canDonate(){ + return false; + } + + /** + * Whether discord RPC is supported. + */ + public boolean hasDiscord(){ + return true; + } + + /** + * Return the localized name for the locale. This is basically a workaround for GWT not supporting getName(). + */ + public String getLocaleName(Locale locale){ + return locale.toString(); + } + + /** + * Whether joining games is supported. + */ + public boolean canJoinGame(){ + return true; + } + + /** + * Whether debug mode is enabled. + */ + public boolean isDebug(){ + return false; + } + + /** + * Must be a base64 string 8 bytes in length. + */ + public String getUUID(){ + String uuid = Settings.getString("uuid", ""); + if(uuid.isEmpty()){ + byte[] result = new byte[8]; + new Random().nextBytes(result); + uuid = new String(Base64Coder.encode(result)); + Settings.putString("uuid", uuid); + Settings.save(); + return uuid; + } + return uuid; + } + + /** + * Only used for iOS or android: open the share menu for a map or save. + */ + public void shareFile(FileHandle file){ + } + + /** + * Download a file. Only used on GWT backend. + */ + public void downloadFile(String name, byte[] bytes){ + } + + /** + * Show a file chooser. Desktop only. * * @param text File chooser title text * @param content Description of the type of files to be loaded @@ -77,25 +141,54 @@ public abstract class Platform { * @param open Whether to open or save files * @param filetype File extension to filter */ - public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype){} - /**Use the default thread provider from the kryonet module for this.*/ - public ThreadProvider getThreadProvider(){ - return new ThreadProvider() { - @Override public boolean isOnThread() {return true;} - @Override public void sleep(long ms) {} - @Override public void start(Runnable run) {} - @Override public void stop() {} - @Override public void notify(Object object) {} - @Override public void wait(Object object) {} - @Override public void switchContainer(EntityGroup group) {} - }; - } + public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype){ + } - //TODO iOS implementation - /**Forces the app into landscape mode. Currently Android only.*/ - public void beginForceLandscape(){} + /** + * Use the default thread provider from the kryonet module for this. + */ + public ThreadProvider getThreadProvider(){ + return new ThreadProvider(){ + @Override + public boolean isOnThread(){ + return true; + } - //TODO iOS implementation - /**Stops forcing the app into landscape orientation. Currently Android only.*/ - public void endForceLandscape(){} + @Override + public void sleep(long ms){ + } + + @Override + public void start(Runnable run){ + } + + @Override + public void stop(){ + } + + @Override + public void notify(Object object){ + } + + @Override + public void wait(Object object){ + } + }; + } + + //TODO iOS implementation + + /** + * Forces the app into landscape mode. Currently Android only. + */ + public void beginForceLandscape(){ + } + + //TODO iOS implementation + + /** + * Stops forcing the app into landscape orientation. Currently Android only. + */ + public void endForceLandscape(){ + } } diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index cf25d06aae..65aa2f3eda 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -47,399 +47,430 @@ import static io.anuke.ucore.core.Core.batch; import static io.anuke.ucore.core.Core.camera; public class Renderer extends RendererModule{ - public Surface effectSurface; - - private int targetscale = baseCameraScale; - private Texture background = new Texture("sprites/background.png"); + public Surface effectSurface; - private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); - private Vector2 avgPosition = new Translator(); - private Vector2 tmpVector1 = new Translator(); - private Vector2 tmpVector2 = new Translator(); + private int targetscale = baseCameraScale; + private Texture background = new Texture("sprites/background.png"); - private BlockRenderer blocks = new BlockRenderer(); - private MinimapRenderer minimap = new MinimapRenderer(); - private OverlayRenderer overlays = new OverlayRenderer(); - private FogRenderer fog = new FogRenderer(); + private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); + private Vector2 avgPosition = new Translator(); + private Vector2 tmpVector1 = new Translator(); + private Vector2 tmpVector2 = new Translator(); - public Renderer() { - pixelate = true; - Lines.setCircleVertices(14); + private BlockRenderer blocks = new BlockRenderer(); + private MinimapRenderer minimap = new MinimapRenderer(); + private OverlayRenderer overlays = new OverlayRenderer(); + private FogRenderer fog = new FogRenderer(); - Shaders.init(); + public Renderer(){ + pixelate = true; + Lines.setCircleVertices(14); - Core.cameraScale = baseCameraScale; - Effects.setEffectProvider((effect, color, x, y, rotation, data) -> { - if(effect == Fx.none) return; - if(Settings.getBool("effects")){ - Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight) - .setCenter(camera.position.x, camera.position.y); - Rectangle pos = rect2.setSize(effect.size).setCenter(x, y); + Shaders.init(); - if(view.overlaps(pos)){ + Core.cameraScale = baseCameraScale; + Effects.setEffectProvider((effect, color, x, y, rotation, data) -> { + if(effect == Fx.none) return; + if(Settings.getBool("effects")){ + Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight) + .setCenter(camera.position.x, camera.position.y); + Rectangle pos = rect2.setSize(effect.size).setCenter(x, y); - if(!(effect instanceof GroundEffect)) { - EffectEntity entity = Pooling.obtain(EffectEntity.class); - entity.effect = effect; - entity.color = color; - entity.rotation = rotation; - entity.data = data; - entity.id ++; - entity.set(x, y); - if(data instanceof BaseEntity){ - entity.setParent((BaseEntity)data); - } - threads.runGraphics(() -> effectGroup.add(entity)); - }else{ - GroundEffectEntity entity = Pooling.obtain(GroundEffectEntity.class); - entity.effect = effect; - entity.color = color; - entity.rotation = rotation; - entity.id ++; - entity.data = data; - entity.set(x, y); - threads.runGraphics(() -> groundEffectGroup.add(entity)); - } - } - } - }); + if(view.overlaps(pos)){ - Cursors.cursorScaling = 3; - Cursors.outlineColor = Color.valueOf("444444"); + if(!(effect instanceof GroundEffect)){ + EffectEntity entity = Pooling.obtain(EffectEntity.class); + entity.effect = effect; + entity.color = color; + entity.rotation = rotation; + entity.data = data; + entity.id++; + entity.set(x, y); + if(data instanceof BaseEntity){ + entity.setParent((BaseEntity) data); + } + threads.runGraphics(() -> effectGroup.add(entity)); + }else{ + GroundEffectEntity entity = Pooling.obtain(GroundEffectEntity.class); + entity.effect = effect; + entity.color = color; + entity.rotation = rotation; + entity.id++; + entity.data = data; + entity.set(x, y); + threads.runGraphics(() -> groundEffectGroup.add(entity)); + } + } + } + }); - Cursors.arrow = Cursors.loadCursor("cursor"); - Cursors.hand = Cursors.loadCursor("hand"); - Cursors.ibeam = Cursors.loadCursor("ibar"); - Cursors.loadCustom("drill"); - Cursors.loadCustom("unload"); + Cursors.cursorScaling = 3; + Cursors.outlineColor = Color.valueOf("444444"); - clearColor = Hue.lightness(0.4f); - clearColor.a = 1f; + Cursors.arrow = Cursors.loadCursor("cursor"); + Cursors.hand = Cursors.loadCursor("hand"); + Cursors.ibeam = Cursors.loadCursor("ibar"); + Cursors.restoreCursor(); + Cursors.loadCustom("drill"); + Cursors.loadCustom("unload"); - background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); - } + clearColor = Hue.lightness(0.4f); + clearColor.a = 1f; - @Override - public void init(){ - int scale = Core.cameraScale; + background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); + } + + @Override + public void init(){ + int scale = Core.cameraScale; effectSurface = Graphics.createSurface(scale); - pixelSurface = Graphics.createSurface(scale); - } + pixelSurface = Graphics.createSurface(scale); + } - @Override - public void update(){ + @Override + public void update(){ - if(Core.cameraScale != targetscale){ - float targetzoom = (float) Core.cameraScale / targetscale; - camera.zoom = Mathf.lerpDelta(camera.zoom, targetzoom, 0.2f); + if(Core.cameraScale != targetscale){ + float targetzoom = (float) Core.cameraScale / targetscale; + camera.zoom = Mathf.lerpDelta(camera.zoom, targetzoom, 0.2f); - if(Mathf.in(camera.zoom, targetzoom, 0.005f)){ - camera.zoom = 1f; - Graphics.setCameraScale(targetscale); - for(Player player : players) { + if(Mathf.in(camera.zoom, targetzoom, 0.005f)){ + camera.zoom = 1f; + Graphics.setCameraScale(targetscale); + for(Player player : players){ control.input(player.playerIndex).resetCursor(); } - } - }else{ - camera.zoom = Mathf.lerpDelta(camera.zoom, 1f, 0.2f); - } + } + }else{ + camera.zoom = Mathf.lerpDelta(camera.zoom, 1f, 0.2f); + } - if(state.is(State.menu)){ - Graphics.clear(Color.BLACK); - }else{ + if(state.is(State.menu)){ + Graphics.clear(Color.BLACK); + }else{ Vector2 position = averagePosition(); if(!mobile){ - setCamera(position.x + 0.0001f, position.y + 0.0001f); - } + setCamera(position.x + 0.0001f, position.y + 0.0001f); + } - clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f); + clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f); - float prex = camera.position.x, prey = camera.position.y; - updateShake(0.75f); + float prex = camera.position.x, prey = camera.position.y; + updateShake(0.75f); - float deltax = camera.position.x - prex, deltay = camera.position.y - prey; - float lastx = camera.position.x, lasty = camera.position.y; - - if(snapCamera){ - camera.position.set((int) camera.position.x, (int) camera.position.y, 0); - } - - if(Gdx.graphics.getHeight() / Core.cameraScale % 2 == 1){ - camera.position.add(0, -0.5f, 0); - } + float deltax = camera.position.x - prex, deltay = camera.position.y - prey; + float lastx = camera.position.x, lasty = camera.position.y; - if(Gdx.graphics.getWidth() / Core.cameraScale % 2 == 1){ - camera.position.add(-0.5f, 0, 0); - } - - draw(); + if(snapCamera){ + camera.position.set((int) camera.position.x, (int) camera.position.y, 0); + } - camera.position.set(lastx - deltax, lasty - deltay, 0); - } + if(Gdx.graphics.getHeight() / Core.cameraScale % 2 == 1){ + camera.position.add(0, -0.5f, 0); + } - if(debug && !ui.chatfrag.chatOpen()) { - renderer.record(); //this only does something if GdxGifRecorder is on the class path, which it usually isn't - } - } + if(Gdx.graphics.getWidth() / Core.cameraScale % 2 == 1){ + camera.position.add(-0.5f, 0, 0); + } - @Override - public void draw(){ - camera.update(); + draw(); - Graphics.clear(clearColor); - - batch.setProjectionMatrix(camera.combined); + camera.position.set(lastx - deltax, lasty - deltay, 0); + } - Graphics.surface(pixelSurface, false); + if(debug && !ui.chatfrag.chatOpen()){ + renderer.record(); //this only does something if GdxGifRecorder is on the class path, which it usually isn't + } + } - drawPadding(); - - blocks.drawFloor(); + @Override + public void draw(){ + camera.update(); - drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait); - drawAndInterpolate(puddleGroup); - drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait)); + Graphics.clear(clearColor); - blocks.processBlocks(); - blocks.drawBlocks(Layer.block); + batch.setProjectionMatrix(camera.combined); - Graphics.shader(Shaders.blockbuild, false); + Graphics.surface(pixelSurface, false); + + drawPadding(); + + blocks.drawFloor(); + + drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait); + drawAndInterpolate(puddleGroup); + drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait)); + + blocks.processBlocks(); + blocks.drawBlocks(Layer.block); + + Graphics.shader(Shaders.blockbuild, false); blocks.drawBlocks(Layer.placement); Graphics.shader(); blocks.drawBlocks(Layer.overlay); if(itemGroup.size() > 0){ - Shaders.outline.color.set(Team.none.color); - - Graphics.beginShaders(Shaders.outline); - drawAndInterpolate(itemGroup); - Graphics.endShaders(); - } + Shaders.outline.color.set(Team.none.color); + Graphics.beginShaders(Shaders.outline); + drawAndInterpolate(itemGroup); + Graphics.endShaders(); + } drawAllTeams(false); - blocks.skipLayer(Layer.turret); - blocks.drawBlocks(Layer.laser); + blocks.skipLayer(Layer.turret); + blocks.drawBlocks(Layer.laser); - drawAllTeams(true); + drawFlyerShadows(); - drawAndInterpolate(bulletGroup); - drawAndInterpolate(effectGroup); + drawAllTeams(true); - overlays.drawBottom(); - drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests); - overlays.drawTop(); + drawAndInterpolate(bulletGroup); + drawAndInterpolate(effectGroup); - Graphics.flushSurface(); + overlays.drawBottom(); + drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests); + overlays.drawTop(); - if(showPaths && debug) drawDebug(); + Graphics.flushSurface(); - batch.end(); + if(showPaths && debug) drawDebug(); - if(showFog){ - fog.draw(); - } + batch.end(); - batch.begin(); - EntityDraw.setClip(false); - drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); - EntityDraw.setClip(true); - batch.end(); - } + if(showFog){ + fog.draw(); + } - private void drawAllTeams(boolean flying){ - for(Team team : Team.all){ - EntityGroup group = unitGroups[team.ordinal()]; + Graphics.beginCam(); + EntityDraw.setClip(false); + drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); + EntityDraw.setClip(true); + Graphics.end(); + } - if(group.count(p -> p.isFlying() == flying) + - playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; + private void drawFlyerShadows(){ + Graphics.surface(effectSurface, true, false); - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder); + float trnsX = 12, trnsY = -13; - Shaders.outline.color.set(team.color); - Shaders.mix.color.set(Color.WHITE); + Graphics.end(); + Core.batch.getTransformMatrix().translate(trnsX, trnsY, 0); + Graphics.begin(); - Graphics.beginShaders(Shaders.outline); - Graphics.shader(Shaders.mix, true); - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead()); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team); - Graphics.shader(); - blocks.drawTeamBlocks(Layer.turret, team); - Graphics.endShaders(); + for(EntityGroup group : unitGroups){ + if(!group.isEmpty()){ + drawAndInterpolate(group, unit -> unit.isFlying() && !unit.isDead(), Unit::drawShadow); + } + } - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); - } - } + if(!playerGroup.isEmpty()){ + drawAndInterpolate(playerGroup, unit -> unit.isFlying() && !unit.isDead(), Unit::drawShadow); + } - public void drawAndInterpolate(EntityGroup group){ - drawAndInterpolate(group, t -> true, DrawTrait::draw); - } + Graphics.end(); + Core.batch.getTransformMatrix().translate(-trnsX, -trnsY, 0); + Graphics.begin(); - public void drawAndInterpolate(EntityGroup group, Predicate toDraw){ - drawAndInterpolate(group, toDraw, DrawTrait::draw); - } + //TODO this actually isn't necessary + Draw.color(0, 0, 0, 0.15f); + Graphics.flushSurface(); + Draw.color(); + } - public void drawAndInterpolate(EntityGroup group, Predicate toDraw, Consumer drawer){ - EntityDraw.drawWith(group, toDraw, t -> { - float lastx = t.getX(), lasty = t.getY(), lastrot = 0f; + private void drawAllTeams(boolean flying){ + for(Team team : Team.all){ + EntityGroup group = unitGroups[team.ordinal()]; - if(threads.doInterpolate() && threads.isEnabled() && t instanceof SolidTrait){ - SolidTrait s = (SolidTrait)t; + if(group.count(p -> p.isFlying() == flying) + + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; - lastrot = s.getRotation(); + drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder); - if(s.lastUpdated() != 0){ - float timeSinceUpdate = TimeUtils.timeSinceMillis(s.lastUpdated()); - float alpha = Math.min(timeSinceUpdate / s.updateSpacing(), 1f); + Shaders.outline.color.set(team.color); + Shaders.mix.color.set(Color.WHITE); - tmpVector1.set(s.lastPosition().x, s.lastPosition().y) - .lerp(tmpVector2.set(lastx, lasty), alpha); - s.setRotation(Mathf.slerp(s.lastPosition().z, lastrot, alpha)); + Graphics.beginShaders(Shaders.outline); + Graphics.shader(Shaders.mix, true); + drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead()); + drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team); + Graphics.shader(); + blocks.drawTeamBlocks(Layer.turret, team); + Graphics.endShaders(); - s.setX(tmpVector1.x); - s.setY(tmpVector1.y); - } - } + drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); + } + } - //TODO extremely hacky - if(t instanceof Player && ((Player) t).getCarry() != null && ((Player) t).getCarry() instanceof Player && ((Player) ((Player) t).getCarry()).isLocal){ - ((Player) t).x = ((Player) t).getCarry().getX(); - ((Player) t).y = ((Player) t).getCarry().getY(); - } + public void drawAndInterpolate(EntityGroup group){ + drawAndInterpolate(group, t -> true, DrawTrait::draw); + } - drawer.accept(t); + public void drawAndInterpolate(EntityGroup group, Predicate toDraw){ + drawAndInterpolate(group, toDraw, DrawTrait::draw); + } - t.setX(lastx); - t.setY(lasty); + public void drawAndInterpolate(EntityGroup group, Predicate toDraw, Consumer drawer){ + EntityDraw.drawWith(group, toDraw, t -> { + float lastx = t.getX(), lasty = t.getY(), lastrot = 0f; - if(threads.doInterpolate() && threads.isEnabled()) { + if(threads.doInterpolate() && threads.isEnabled() && t instanceof SolidTrait){ + SolidTrait s = (SolidTrait) t; - if (t instanceof SolidTrait) { - ((SolidTrait) t).setRotation(lastrot); - } - } - }); - } + lastrot = s.getRotation(); - @Override - public void resize(int width, int height){ - super.resize(width, height); - for(Player player : players) { + if(s.lastUpdated() != 0){ + float timeSinceUpdate = TimeUtils.timeSinceMillis(s.lastUpdated()); + float alpha = Math.min(timeSinceUpdate / s.updateSpacing(), 1f); + + tmpVector1.set(s.lastPosition().x, s.lastPosition().y) + .lerp(tmpVector2.set(lastx, lasty), alpha); + s.setRotation(Mathf.slerp(s.lastPosition().z, lastrot, alpha)); + + s.setX(tmpVector1.x); + s.setY(tmpVector1.y); + } + } + + //TODO extremely hacky + if(t instanceof Player && ((Player) t).getCarry() != null && ((Player) t).getCarry() instanceof Player && ((Player) ((Player) t).getCarry()).isLocal){ + ((Player) t).x = ((Player) t).getCarry().getX(); + ((Player) t).y = ((Player) t).getCarry().getY(); + } + + drawer.accept(t); + + t.setX(lastx); + t.setY(lasty); + + if(threads.doInterpolate() && threads.isEnabled()){ + + if(t instanceof SolidTrait){ + ((SolidTrait) t).setRotation(lastrot); + } + } + }); + } + + @Override + public void resize(int width, int height){ + super.resize(width, height); + for(Player player : players){ control.input(player.playerIndex).resetCursor(); } - camera.position.set(players[0].x, players[0].y, 0); - } + camera.position.set(players[0].x, players[0].y, 0); + } - @Override - public void dispose() { - background.dispose(); - fog.dispose(); - } + @Override + public void dispose(){ + background.dispose(); + fog.dispose(); + } - public Vector2 averagePosition(){ - avgPosition.setZero(); + public Vector2 averagePosition(){ + avgPosition.setZero(); - drawAndInterpolate(playerGroup, p -> p.isLocal, p -> { - avgPosition.add(p.x, p.y); - }); + drawAndInterpolate(playerGroup, p -> p.isLocal, p -> { + avgPosition.add(p.x, p.y); + }); avgPosition.scl(1f / players.length); return avgPosition; } - public FogRenderer fog() { - return fog; - } + public FogRenderer fog(){ + return fog; + } - public MinimapRenderer minimap() { - return minimap; - } + public MinimapRenderer minimap(){ + return minimap; + } - void drawPadding(){ - float vw = world.width() * tilesize; - float cw = camera.viewportWidth * camera.zoom; - float ch = camera.viewportHeight * camera.zoom; - if(vw < cw){ - batch.draw(background, - camera.position.x + vw/2, - Mathf.round(camera.position.y - ch/2, tilesize), - (cw - vw) /2, - ch + tilesize, - 0, 0, - ((cw - vw) / 2 / tilesize), -ch / tilesize + 1); + void drawPadding(){ + float vw = world.width() * tilesize; + float cw = camera.viewportWidth * camera.zoom; + float ch = camera.viewportHeight * camera.zoom; + if(vw < cw){ + batch.draw(background, + camera.position.x + vw / 2, + Mathf.round(camera.position.y - ch / 2, tilesize), + (cw - vw) / 2, + ch + tilesize, + 0, 0, + ((cw - vw) / 2 / tilesize), -ch / tilesize + 1); - batch.draw(background, - camera.position.x - vw/2, - Mathf.round(camera.position.y - ch/2, tilesize), - -(cw - vw) /2, - ch + tilesize, - 0, 0, - -((cw - vw) / 2 / tilesize), -ch / tilesize + 1); - } - } + batch.draw(background, + camera.position.x - vw / 2, + Mathf.round(camera.position.y - ch / 2, tilesize), + -(cw - vw) / 2, + ch + tilesize, + 0, 0, + -((cw - vw) / 2 / tilesize), -ch / tilesize + 1); + } + } - void drawDebug(){ - int rangex = (int)(Core.camera.viewportWidth/tilesize/2), rangey = (int)(Core.camera.viewportHeight/tilesize/2); + void drawDebug(){ + int rangex = (int) (Core.camera.viewportWidth / tilesize / 2), rangey = (int) (Core.camera.viewportHeight / tilesize / 2); - for(int x = -rangex; x <= rangex; x++) { - for (int y = -rangey; y <= rangey; y++) { - int worldx = Mathf.scl(camera.position.x, tilesize) + x; - int worldy = Mathf.scl(camera.position.y, tilesize) + y; + for(int x = -rangex; x <= rangex; x++){ + for(int y = -rangey; y <= rangey; y++){ + int worldx = Mathf.scl(camera.position.x, tilesize) + x; + int worldy = Mathf.scl(camera.position.y, tilesize) + y; - if(world.tile(worldx, worldy) == null) continue; + if(world.tile(worldx, worldy) == null) continue; - float value = world.pathfinder().getDebugValue(worldx, worldy); - Draw.color(Color.PURPLE); - Draw.alpha((value % 10f) / 10f); - Lines.square(worldx * tilesize, worldy*tilesize, 4f); - } - } + float value = world.pathfinder().getDebugValue(worldx, worldy); + Draw.color(Color.PURPLE); + Draw.alpha((value % 10f) / 10f); + Lines.square(worldx * tilesize, worldy * tilesize, 4f); + } + } - Draw.color(Color.ORANGE); - Draw.tcolor(Color.ORANGE); + Draw.color(Color.ORANGE); + Draw.tcolor(Color.ORANGE); - ObjectIntMap seen = new ObjectIntMap<>(); + ObjectIntMap seen = new ObjectIntMap<>(); - for(BlockFlag flag : BlockFlag.values()){ - for(Tile tile : world.indexer().getEnemy(Team.blue, flag)){ - int index = seen.getAndIncrement(tile, 0, 1); - Draw.tscl(0.125f); - Draw.text(flag.name(), tile.drawx(), tile.drawy() + tile.block().size * tilesize/2f + 4 + index * 3); - Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f); - } - } - Draw.tscl(fontScale); - Draw.tcolor(); + for(BlockFlag flag : BlockFlag.values()){ + for(Tile tile : world.indexer().getEnemy(Team.blue, flag)){ + int index = seen.getAndIncrement(tile, 0, 1); + Draw.tscl(0.125f); + Draw.text(flag.name(), tile.drawx(), tile.drawy() + tile.block().size * tilesize / 2f + 4 + index * 3); + Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f); + } + } + Draw.tscl(fontScale); + Draw.tcolor(); - Draw.color(); - } + Draw.color(); + } - public BlockRenderer getBlocks() { - return blocks; - } + public BlockRenderer getBlocks(){ + return blocks; + } - public void setCameraScale(int amount){ - targetscale = amount; - clampScale(); - //scale up all surfaces in preparation for the zoom - for(Surface surface : Graphics.getSurfaces()){ - surface.setScale(targetscale); - } - } + public void setCameraScale(int amount){ + targetscale = amount; + clampScale(); + //scale up all surfaces in preparation for the zoom + for(Surface surface : Graphics.getSurfaces()){ + surface.setScale(targetscale); + } + } - public void scaleCamera(int amount){ - setCameraScale(targetscale + amount); - } + public void scaleCamera(int amount){ + setCameraScale(targetscale + amount); + } - public void clampScale(){ - float s = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(1f); - targetscale = Mathf.clamp(targetscale, Math.round(s*2), Math.round(s*5)); - } + public void clampScale(){ + float s = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(1f); + targetscale = Mathf.clamp(targetscale, Math.round(s * 2), Math.round(s * 5)); + } } diff --git a/core/src/io/anuke/mindustry/core/ThreadHandler.java b/core/src/io/anuke/mindustry/core/ThreadHandler.java index e127b94941..22bc5ff2fe 100644 --- a/core/src/io/anuke/mindustry/core/ThreadHandler.java +++ b/core/src/io/anuke/mindustry/core/ThreadHandler.java @@ -1,43 +1,38 @@ package io.anuke.mindustry.core; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Queue; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.ucore.core.Timers; -import io.anuke.ucore.entities.Entities; -import io.anuke.ucore.entities.EntityGroup; -import io.anuke.ucore.entities.EntityGroup.ArrayContainer; -import io.anuke.ucore.entities.trait.Entity; import io.anuke.ucore.util.Log; import static io.anuke.mindustry.Vars.control; import static io.anuke.mindustry.Vars.logic; -public class ThreadHandler { - private final Array toRun = new Array<>(); +public class ThreadHandler{ + private final Queue toRun = new Queue<>(); private final ThreadProvider impl; + private final Object updateLock = new Object(); private float delta = 1f; private float smoothDelta = 1f; private long frame = 0, lastDeltaUpdate; private float framesSinceUpdate; private boolean enabled; - - private final Object updateLock = new Object(); private boolean rendered = true; public ThreadHandler(ThreadProvider impl){ this.impl = impl; Timers.setDeltaProvider(() -> { - float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime()*60f; + float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f; return Math.min(Float.isNaN(result) ? 1f : result, 15f); }); } public void run(Runnable r){ - if(enabled) { - synchronized (toRun) { - toRun.add(r); + if(enabled){ + synchronized(toRun){ + toRun.addLast(r); } }else{ r.run(); @@ -45,7 +40,7 @@ public class ThreadHandler { } public void runGraphics(Runnable r){ - if(enabled) { + if(enabled){ Gdx.app.postRunnable(r); }else{ r.run(); @@ -53,9 +48,9 @@ public class ThreadHandler { } public void runDelay(Runnable r){ - if(enabled) { - synchronized (toRun) { - toRun.add(r); + if(enabled){ + synchronized(toRun){ + toRun.addLast(r); } }else{ Gdx.app.postRunnable(r); @@ -63,7 +58,7 @@ public class ThreadHandler { } public int getTPS(){ - return (int)(60/smoothDelta); + return (int) (60 / smoothDelta); } public long getFrameID(){ @@ -80,40 +75,34 @@ public class ThreadHandler { framesSinceUpdate += Timers.delta(); - synchronized (updateLock) { + synchronized(updateLock){ rendered = true; impl.notify(updateLock); } } - public void setEnabled(boolean enabled){ - if(enabled){ - logic.doUpdate = false; - for(EntityGroup group : Entities.getAllGroups()){ - impl.switchContainer(group); - } - Timers.runTask(2f, () -> { - impl.start(this::runLogic); - this.enabled = true; - }); - }else{ - this.enabled = false; - impl.stop(); - for(EntityGroup group : Entities.getAllGroups()){ - group.setContainer(new ArrayContainer<>()); - } - Timers.runTask(2f, () -> { - logic.doUpdate = true; - }); - } - } - public boolean isEnabled(){ return enabled; } + public void setEnabled(boolean enabled){ + if(enabled){ + logic.doUpdate = false; + Timers.runTask(2f, () -> { + impl.start(this::runLogic); + this.enabled = true; + }); + }else{ + this.enabled = false; + impl.stop(); + Timers.runTask(2f, () -> { + logic.doUpdate = true; + }); + } + } + public boolean doInterpolate(){ - return enabled && Math.abs(Gdx.graphics.getFramesPerSecond() - getTPS()) > 15; + return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30; } public boolean isOnThread(){ @@ -121,15 +110,21 @@ public class ThreadHandler { } private void runLogic(){ - try { - while (true) { + try{ + while(true){ long time = TimeUtils.nanoTime(); - synchronized (toRun) { - for(Runnable r : toRun){ - r.run(); + while(true){ + Runnable r; + synchronized(toRun){ + if(toRun.size > 0){ + r = toRun.removeFirst(); + }else{ + break; + } } - toRun.clear(); + + r.run(); } logic.doUpdate = true; @@ -139,12 +134,12 @@ public class ThreadHandler { long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time)); long target = (long) ((1000) / 60f); - if (elapsed < target) { + if(elapsed < target){ impl.sleep(target - elapsed); } - synchronized(updateLock) { - while(!rendered) { + synchronized(updateLock){ + while(!rendered){ impl.wait(updateLock); } rendered = false; @@ -158,23 +153,27 @@ public class ThreadHandler { smoothDelta = delta; } - frame ++; + frame++; framesSinceUpdate = 0; } - } catch (InterruptedException ex) { + }catch(InterruptedException ex){ Log.info("Stopping logic thread."); - } catch (Throwable ex) { + }catch(Throwable ex){ control.setError(ex); } } - public interface ThreadProvider { + public interface ThreadProvider{ boolean isOnThread(); + void sleep(long ms) throws InterruptedException; + void start(Runnable run); + void stop(); + void wait(Object object) throws InterruptedException; + void notify(Object object); - void switchContainer(EntityGroup group); } } diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index be54f94247..d57d230993 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -34,32 +34,11 @@ import java.util.Locale; import static io.anuke.mindustry.Vars.control; import static io.anuke.mindustry.Vars.players; +import static io.anuke.mindustry.Vars.threads; import static io.anuke.ucore.scene.actions.Actions.*; public class UI extends SceneModule{ - public AboutDialog about; - public RestartDialog restart; - public LevelDialog levels; - public MapsDialog maps; - public LoadDialog load; - public DiscordDialog discord; - public JoinDialog join; - public HostDialog host; - public PausedDialog paused; - public SettingsMenuDialog settings; - public ControlsDialog controls; - public MapEditorDialog editor; - public LanguageDialog language; - public BansDialog bans; - public AdminsDialog admins; - public TraceDialog traces; - public RollbackDialog rollback; - public ChangelogDialog changelog; - public LocalPlayerDialog localplayers; - public UnlocksDialog unlocks; - public ContentInfoDialog content; - - public final MenuFragment menufrag = new MenuFragment(); + public final MenuFragment menufrag = new MenuFragment(); public final HudFragment hudfrag = new HudFragment(); public final ChatFragment chatfrag = new ChatFragment(); public final PlayerListFragment listfrag = new PlayerListFragment(); @@ -67,239 +46,260 @@ public class UI extends SceneModule{ public final LoadingFragment loadfrag = new LoadingFragment(); public final DebugFragment debugfrag = new DebugFragment(); + public AboutDialog about; + public RestartDialog restart; + public LevelDialog levels; + public MapsDialog maps; + public LoadDialog load; + public DiscordDialog discord; + public JoinDialog join; + public HostDialog host; + public PausedDialog paused; + public SettingsMenuDialog settings; + public ControlsDialog controls; + public MapEditorDialog editor; + public LanguageDialog language; + public BansDialog bans; + public AdminsDialog admins; + public TraceDialog traces; + public RollbackDialog rollback; + public ChangelogDialog changelog; + public LocalPlayerDialog localplayers; + public UnlocksDialog unlocks; + public ContentInfoDialog content; + private Locale lastLocale; - - public UI() { - Dialog.setShowAction(()-> sequence( - alpha(0f), - originCenter(), - moveToAligned(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2, Align.center), - scaleTo(0.0f, 1f), - parallel( - scaleTo(1f, 1f, 0.1f, Interpolation.fade), - fadeIn(0.1f, Interpolation.fade) - ) - )); - - Dialog.setHideAction(()-> sequence( - parallel( - scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade), - fadeOut(0.1f, Interpolation.fade) - ) - )); - - TooltipManager.getInstance().animations = false; - - Settings.setErrorHandler(()-> Timers.run(1f, ()-> showError("[crimson]Failed to access local storage.\nSettings will not be saved."))); - - Dialog.closePadR = -1; - Dialog.closePadT = 5; - - Colors.put("description", Palette.description); - Colors.put("turretinfo", Palette.turretinfo); - Colors.put("iteminfo", Palette.iteminfo); - Colors.put("powerinfo", Palette.powerinfo); - Colors.put("liquidinfo", Palette.liquidinfo); - Colors.put("craftinfo", Palette.craftinfo); - Colors.put("missingitems", Palette.missingitems); - Colors.put("health", Palette.health); - Colors.put("healthstats", Palette.healthstats); - Colors.put("interact", Palette.interact); - Colors.put("accent", Palette.accent); - Colors.put("place", Palette.place); - Colors.put("remove", Palette.remove); - Colors.put("placeRotate", Palette.placeRotate); - Colors.put("range", Palette.range); - Colors.put("power", Palette.power); - } - @Override - protected void loadSkin(){ - skin = new Skin(Gdx.files.internal("ui/uiskin.json"), Core.atlas); - Mathf.each(font -> { - font.setUseIntegerPositions(false); - font.getData().setScale(Vars.fontScale); - font.getData().down += Unit.dp.scl(4f); - font.getData().lineHeight -= Unit.dp.scl(2f); - }, skin.font(), skin.getFont("default-font-chat"), skin.getFont("korean")); - } + public UI(){ + Dialog.setShowAction(() -> sequence( + alpha(0f), + originCenter(), + moveToAligned(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, Align.center), + scaleTo(0.0f, 1f), + parallel( + scaleTo(1f, 1f, 0.1f, Interpolation.fade), + fadeIn(0.1f, Interpolation.fade) + ) + )); - @Override - public synchronized void update(){ - if(Vars.debug && !Vars.showUI) return; + Dialog.setHideAction(() -> sequence( + parallel( + scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade), + fadeOut(0.1f, Interpolation.fade) + ) + )); - if(Graphics.drawing()) Graphics.end(); - - act(); + TooltipManager.getInstance().animations = false; - Graphics.begin(); + Settings.setErrorHandler(() -> Timers.run(1f, () -> showError("[crimson]Failed to access local storage.\nSettings will not be saved."))); - for(int i = 0; i < players.length; i ++){ - InputHandler input = control.input(i); + Dialog.closePadR = -1; + Dialog.closePadT = 5; - if(input.isCursorVisible()) { + Colors.put("description", Palette.description); + Colors.put("turretinfo", Palette.turretinfo); + Colors.put("iteminfo", Palette.iteminfo); + Colors.put("powerinfo", Palette.powerinfo); + Colors.put("liquidinfo", Palette.liquidinfo); + Colors.put("craftinfo", Palette.craftinfo); + Colors.put("missingitems", Palette.missingitems); + Colors.put("health", Palette.health); + Colors.put("healthstats", Palette.healthstats); + Colors.put("interact", Palette.interact); + Colors.put("accent", Palette.accent); + Colors.put("place", Palette.place); + Colors.put("remove", Palette.remove); + Colors.put("placeRotate", Palette.placeRotate); + Colors.put("range", Palette.range); + Colors.put("power", Palette.power); + } + + @Override + protected void loadSkin(){ + skin = new Skin(Gdx.files.internal("ui/uiskin.json"), Core.atlas); + Mathf.each(font -> { + font.setUseIntegerPositions(false); + font.getData().setScale(Vars.fontScale); + font.getData().down += Unit.dp.scl(4f); + font.getData().lineHeight -= Unit.dp.scl(2f); + }, skin.font(), skin.getFont("default-font-chat"), skin.getFont("korean")); + } + + @Override + public synchronized void update(){ + if(Vars.debug && !Vars.showUI) return; + + if(Graphics.drawing()) Graphics.end(); + + act(); + + Graphics.begin(); + + for(int i = 0; i < players.length; i++){ + InputHandler input = control.input(i); + + if(input.isCursorVisible()){ Draw.color(); float scl = Unit.dp.scl(3f); - Draw.rect("controller-cursor", input.getMouseX(), Gdx.graphics.getHeight() - input.getMouseY(), 16*scl, 16*scl); + Draw.rect("controller-cursor", input.getMouseX(), Gdx.graphics.getHeight() - input.getMouseY(), 16 * scl, 16 * scl); } } - Graphics.end(); + Graphics.end(); + Draw.color(); + } - } + @Override + public void init(){ + editor = new MapEditorDialog(); + controls = new ControlsDialog(); + restart = new RestartDialog(); + join = new JoinDialog(); + discord = new DiscordDialog(); + load = new LoadDialog(); + levels = new LevelDialog(); + language = new LanguageDialog(); + settings = new SettingsMenuDialog(); + paused = new PausedDialog(); + changelog = new ChangelogDialog(); + about = new AboutDialog(); + host = new HostDialog(); + bans = new BansDialog(); + admins = new AdminsDialog(); + traces = new TraceDialog(); + rollback = new RollbackDialog(); + maps = new MapsDialog(); + localplayers = new LocalPlayerDialog(); + unlocks = new UnlocksDialog(); + content = new ContentInfoDialog(); - @Override - public void init(){ - editor = new MapEditorDialog(); - controls = new ControlsDialog(); - restart = new RestartDialog(); - join = new JoinDialog(); - discord = new DiscordDialog(); - load = new LoadDialog(); - levels = new LevelDialog(); - language = new LanguageDialog(); - settings = new SettingsMenuDialog(); - paused = new PausedDialog(); - changelog = new ChangelogDialog(); - about = new AboutDialog(); - host = new HostDialog(); - bans = new BansDialog(); - admins = new AdminsDialog(); - traces = new TraceDialog(); - rollback = new RollbackDialog(); - maps = new MapsDialog(); - localplayers = new LocalPlayerDialog(); - unlocks = new UnlocksDialog(); - content = new ContentInfoDialog(); + build.begin(scene); - build.begin(scene); + Group group = Core.scene.getRoot(); - Group group = Core.scene.getRoot(); + backfrag.build(group); + hudfrag.build(group); + menufrag.build(group); + chatfrag.container().build(group); + listfrag.build(group); + debugfrag.build(group); + loadfrag.build(group); - backfrag.build(group); - hudfrag.build(group); - menufrag.build(group); - chatfrag.container().build(group); - listfrag.build(group); - debugfrag.build(group); - loadfrag.build(group); + build.end(); + } - build.end(); - } + @Override + public boolean hasMouse(){ + return super.hasMouse(); + } - @Override - public boolean hasMouse() { - return super.hasMouse(); - } + @Override + public void resize(int width, int height){ + super.resize(width, height); - @Override - public void resize(int width, int height) { - super.resize(width, height); + Events.fire(ResizeEvent.class); + } - Events.fire(ResizeEvent.class); - } + public Locale getLocale(){ + String loc = Settings.getString("locale"); + if(loc.equals("default")){ + return Locale.getDefault(); + }else{ + if(lastLocale == null || !lastLocale.toString().equals(loc)){ + if(loc.contains("_")){ + String[] split = loc.split("_"); + lastLocale = new Locale(split[0], split[1]); + }else{ + lastLocale = new Locale(loc); + } + } - public Locale getLocale(){ - String loc = Settings.getString("locale"); - if(loc.equals("default")){ - return Locale.getDefault(); - }else{ - if(lastLocale == null || !lastLocale.toString().equals(loc)){ - if(loc.contains("_")){ - String[] split = loc.split("_"); - lastLocale = new Locale(split[0], split[1]); - }else{ - lastLocale = new Locale(loc); - } - } + return lastLocale; + } + } - return lastLocale; - } - } + public void loadAnd(Callable call){ + loadAnd("$text.loading", call); + } - public void loadAnd(Callable call){ - loadAnd("$text.loading", call); - } + public void loadAnd(String text, Callable call){ + loadfrag.show(text); + Timers.runTask(7f, () -> { + call.run(); + loadfrag.hide(); + }); + } - public void loadAnd(String text, Callable call){ - loadfrag.show(text); - Timers.runTask(6f, () -> { - call.run(); - loadfrag.hide(); - }); - } + public void loadLogic(Callable call){ + loadLogic("$text.loading", call); + } - public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer confirmed){ - new Dialog(title, "dialog"){{ - content().margin(30).add(text).padRight(6f); - TextField field = content().addField(def, t->{}).size(170f, 50f).get(); - field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c)); - Platform.instance.addDialog(field); - buttons().defaults().size(120, 54).pad(4); - buttons().addButton("$text.ok", () -> { - confirmed.accept(field.getText()); - hide(); - }).disabled(b -> field.getText().isEmpty()); - buttons().addButton("$text.cancel", this::hide); - }}.show(); - } + public void loadLogic(String text, Callable call){ + loadfrag.show(); + Timers.runTask(7f, () -> { + threads.run(() -> { + call.run(); + threads.runGraphics(loadfrag::hide); + }); + }); + } - public void showTextInput(String title, String text, String def, Consumer confirmed){ - showTextInput(title, text, def, (field, c) -> true, confirmed); - } + public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer confirmed){ + new Dialog(title, "dialog"){{ + content().margin(30).add(text).padRight(6f); + TextField field = content().addField(def, t -> { + }).size(170f, 50f).get(); + field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c)); + Platform.instance.addDialog(field); + buttons().defaults().size(120, 54).pad(4); + buttons().addButton("$text.ok", () -> { + confirmed.accept(field.getText()); + hide(); + }).disabled(b -> field.getText().isEmpty()); + buttons().addButton("$text.cancel", this::hide); + }}.show(); + } - public void showInfoFade(String info){ - Table table = new Table(); - table.setFillParent(true); - table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor()); - table.top().add(info).padTop(8); - Core.scene.add(table); - } + public void showTextInput(String title, String text, String def, Consumer confirmed){ + showTextInput(title, text, def, (field, c) -> true, confirmed); + } - public void showInfo(String info){ - new Dialog("$text.info.title", "dialog"){{ - getCell(content()).growX(); - content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center); - buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); - }}.show(); - } + public void showInfoFade(String info){ + Table table = new Table(); + table.setFillParent(true); + table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor()); + table.top().add(info).padTop(8); + Core.scene.add(table); + } - public void showError(String text){ - new Dialog("$text.error.title", "dialog"){{ - content().margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center); - buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); - }}.show(); - } + public void showInfo(String info){ + new Dialog("$text.info.title", "dialog"){{ + getCell(content()).growX(); + content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center); + buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); + }}.show(); + } - public void showConfirm(String title, String text, Listenable confirmed){ - FloatingDialog dialog = new FloatingDialog(title); - dialog.content().add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center); - dialog.buttons().defaults().size(200f, 54f).pad(2f); - dialog.buttons().addButton("$text.cancel", dialog::hide); - dialog.buttons().addButton("$text.ok", () -> { - dialog.hide(); - confirmed.listen(); - }); - dialog.keyDown(Keys.ESCAPE, dialog::hide); - dialog.keyDown(Keys.BACK, dialog::hide); - dialog.show(); - } + public void showError(String text){ + new Dialog("$text.error.title", "dialog"){{ + content().margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center); + buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); + }}.show(); + } - public void showConfirmListen(String title, String text, Consumer listener){ - FloatingDialog dialog = new FloatingDialog(title); - dialog.content().add(text).pad(4f); - dialog.buttons().defaults().size(200f, 54f).pad(2f); - dialog.buttons().addButton("$text.cancel", () -> { - dialog.hide(); - listener.accept(true); - }); - dialog.buttons().addButton("$text.ok", () -> { - dialog.hide(); - listener.accept(true); - }); - dialog.show(); - } - + public void showConfirm(String title, String text, Listenable confirmed){ + FloatingDialog dialog = new FloatingDialog(title); + dialog.content().add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center); + dialog.buttons().defaults().size(200f, 54f).pad(2f); + dialog.buttons().addButton("$text.cancel", dialog::hide); + dialog.buttons().addButton("$text.ok", () -> { + dialog.hide(); + confirmed.listen(); + }); + dialog.keyDown(Keys.ESCAPE, dialog::hide); + dialog.keyDown(Keys.BACK, dialog::hide); + dialog.show(); + } } diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index a139ecbf39..0a6a0300de 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -10,7 +10,11 @@ import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent; -import io.anuke.mindustry.io.*; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.io.Map; +import io.anuke.mindustry.io.MapIO; +import io.anuke.mindustry.io.MapMeta; +import io.anuke.mindustry.io.Maps; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.mapgen.WorldGenerator; @@ -26,124 +30,130 @@ import io.anuke.ucore.util.Tmp; import static io.anuke.mindustry.Vars.*; public class World extends Module{ - private int seed; - - private Map currentMap; - private Tile[][] tiles; - private Pathfinder pathfinder = new Pathfinder(); - private BlockIndexer indexer = new BlockIndexer(); - private Maps maps = new Maps(); + private int seed; - private Array tempTiles = new ThreadArray<>(); - private boolean generating, invalidMap; - - public World(){ - maps.load(); - } - - @Override - public void dispose(){ - maps.dispose(); - } - - public Maps maps(){ - return maps; - } + private Map currentMap; + private Tile[][] tiles; + private Pathfinder pathfinder = new Pathfinder(); + private BlockIndexer indexer = new BlockIndexer(); + private Maps maps = new Maps(); - public BlockIndexer indexer() { - return indexer; - } + private Array tempTiles = new ThreadArray<>(); + private boolean generating, invalidMap; - public Pathfinder pathfinder(){ - return pathfinder; - } + public World(){ + maps.load(); + } - public boolean isInvalidMap() { - return invalidMap; - } + @Override + public void dispose(){ + maps.dispose(); + } - public boolean solid(int x, int y){ - Tile tile = tile(x, y); - - return tile == null || tile.solid(); - } - - public boolean passable(int x, int y){ - Tile tile = tile(x, y); - - return tile != null && tile.passable(); - } - - public boolean wallSolid(int x, int y){ - Tile tile = tile(x, y); - return tile == null || tile.block().solid; - } - - public boolean isAccessible(int x, int y){ - return !wallSolid(x, y-1) || !wallSolid(x, y+1) || !wallSolid(x-1, y) ||!wallSolid(x+1, y); - } - - public boolean floorBlends(int x, int y, Block block){ - Tile tile = tile(x, y); - return tile == null || tile.floor().id <= block.id; - } - - public Map getMap(){ - return currentMap; - } - - public int width(){ - return tiles.length; - } - - public int height(){ - return tiles[0].length; - } + public Maps maps(){ + return maps; + } - public int toPacked(int x, int y){ - return x + y *width(); - } + public BlockIndexer indexer(){ + return indexer; + } - public Tile tile(int packed){ - return tiles == null ? null : tile(packed % width(), packed / width()); - } - - public Tile tile(int x, int y){ - if(tiles == null){ - return null; - } - if(!Mathf.inBounds(x, y, tiles)) return null; - return tiles[x][y]; - } + public Pathfinder pathfinder(){ + return pathfinder; + } - public Tile rawTile(int x, int y){ - return tiles[x][y]; - } - - public Tile tileWorld(float x, float y){ - return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize)); - } + public boolean isInvalidMap(){ + return invalidMap; + } - public int toTile(float coord){ - return Mathf.scl2(coord, tilesize); - } - - public Tile[][] getTiles(){ - return tiles; - } - - private void clearTileEntities(){ - for(int x = 0; x < tiles.length; x ++){ - for(int y = 0; y < tiles[0].length; y ++){ - if(tiles[x][y] != null && tiles[x][y].entity != null){ - tiles[x][y].entity.remove(); - } - } - } - } + public boolean solid(int x, int y){ + Tile tile = tile(x, y); - /**Resizes the tile array to the specified size and returns the resulting tile array. - * Only use for loading saves!*/ + return tile == null || tile.solid(); + } + + public boolean passable(int x, int y){ + Tile tile = tile(x, y); + + return tile != null && tile.passable(); + } + + public boolean wallSolid(int x, int y){ + Tile tile = tile(x, y); + return tile == null || tile.block().solid; + } + + public boolean isAccessible(int x, int y){ + return !wallSolid(x, y - 1) || !wallSolid(x, y + 1) || !wallSolid(x - 1, y) || !wallSolid(x + 1, y); + } + + public boolean floorBlends(int x, int y, Block block){ + Tile tile = tile(x, y); + return tile == null || tile.floor().id <= block.id; + } + + public Map getMap(){ + return currentMap; + } + + public void setMap(Map map){ + this.currentMap = map; + } + + public int width(){ + return tiles == null ? 0 : tiles.length; + } + + public int height(){ + return tiles == null ? 0 : tiles[0].length; + } + + public int toPacked(int x, int y){ + return x + y * width(); + } + + public Tile tile(int packed){ + return tiles == null ? null : tile(packed % width(), packed / width()); + } + + public Tile tile(int x, int y){ + if(tiles == null){ + return null; + } + if(!Mathf.inBounds(x, y, tiles)) return null; + return tiles[x][y]; + } + + public Tile rawTile(int x, int y){ + return tiles[x][y]; + } + + public Tile tileWorld(float x, float y){ + return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize)); + } + + public int toTile(float coord){ + return Mathf.scl2(coord, tilesize); + } + + public Tile[][] getTiles(){ + return tiles; + } + + private void clearTileEntities(){ + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ + if(tiles[x][y] != null && tiles[x][y].entity != null){ + tiles[x][y].entity.remove(); + } + } + } + } + + /** + * Resizes the tile array to the specified size and returns the resulting tile array. + * Only use for loading saves! + */ public Tile[][] createTiles(int width, int height){ if(tiles != null){ clearTileEntities(); @@ -158,181 +168,214 @@ public class World extends Module{ return tiles; } - /**Call to signify the beginning of map loading. - * TileChangeEvents will not be fired until endMapLoad().*/ - public void beginMapLoad(){ - generating = true; - } + /** + * Call to signify the beginning of map loading. + * TileChangeEvents will not be fired until endMapLoad(). + */ + public void beginMapLoad(){ + generating = true; + } - /**Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world. - * A WorldLoadEvent will be fire.*/ - public void endMapLoad(){ - for(int x = 0; x < tiles.length; x ++) { - for (int y = 0; y < tiles[0].length; y++) { - tiles[x][y].updateOcclusion(); - } - } + /** + * Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world. + * A WorldLoadEvent will be fire. + */ + public void endMapLoad(){ + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ + tiles[x][y].updateOcclusion(); - EntityPhysics.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize); + if(tiles[x][y].entity != null){ + tiles[x][y].entity.updateProximity(); + } + } + } - generating = false; - Events.fire(WorldLoadEvent.class); - } + EntityPhysics.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize); - /**Loads up a procedural map. This does not call play(), but calls reset().*/ - public void loadProceduralMap(){ - Timers.mark(); - Timers.mark(); + generating = false; + Events.fire(WorldLoadEvent.class); + } - logic.reset(); + /** + * Loads up a procedural map. This does not call play(), but calls reset(). + */ + public void loadProceduralMap(){ + Timers.mark(); + Timers.mark(); - beginMapLoad(); + logic.reset(); - int width = 400, height = 400; + beginMapLoad(); - Tile[][] tiles = createTiles(width, height); + int width = 400, height = 400; - Map map = new Map("Generated Map", new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null); - setMap(map); + Tile[][] tiles = createTiles(width, height); - EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize); + Map map = new Map("Generated Map", new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null); + setMap(map); - Timers.mark(); - WorldGenerator.generateMap(tiles, Mathf.random(9999999)); - Log.info("Time to generate base map: {0}", Timers.elapsed()); + EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize); - Log.info("Time to generate fully without additional events: {0}", Timers.elapsed()); + Timers.mark(); + WorldGenerator.generateMap(tiles, Mathf.random(9999999)); + Log.info("Time to generate base map: {0}", Timers.elapsed()); - endMapLoad(); + Log.info("Time to generate fully without additional events: {0}", Timers.elapsed()); - Log.info("Full time to generate: {0}", Timers.elapsed()); - } + endMapLoad(); - public void setMap(Map map){ - this.currentMap = map; - } - - public void loadMap(Map map){ - loadMap(map, MathUtils.random(0, 999999)); - } - - public void loadMap(Map map, int seed){ - beginMapLoad(); - this.currentMap = map; - this.seed = seed; + Log.info("Full time to generate: {0}", Timers.elapsed()); + } - int width = map.meta.width, height = map.meta.height; + public void loadMap(Map map){ + loadMap(map, MathUtils.random(0, 999999)); + } - createTiles(width, height); - - EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize); + public void loadMap(Map map, int seed){ + beginMapLoad(); + this.currentMap = map; + this.seed = seed; - WorldGenerator.loadTileData(tiles, MapIO.readTileData(map, true), map.meta.hasOreGen(), seed); + int width = map.meta.width, height = map.meta.height; - if(!headless && state.teams.get(players[0].getTeam()).cores.size == 0){ - ui.showError("$text.map.nospawn"); - threads.runDelay(() -> state.set(State.menu)); - invalidMap = true; - }else{ - invalidMap = false; - } + createTiles(width, height); - endMapLoad(); - } + EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize); - public int getSeed(){ - return seed; - } + WorldGenerator.loadTileData(tiles, MapIO.readTileData(map, true), map.meta.hasOreGen(), seed); - public void notifyChanged(Tile tile){ - if(!generating){ - threads.runDelay(() -> Events.fire(TileChangeEvent.class, tile)); - } - } + if(!headless && state.teams.get(players[0].getTeam()).cores.size == 0){ + ui.showError("$text.map.nospawn"); + threads.runDelay(() -> state.set(State.menu)); + invalidMap = true; + }else{ + invalidMap = false; + } - public void removeBlock(Tile tile){ - if(!tile.block().isMultiblock() && !tile.isLinked()){ - tile.setBlock(Blocks.air); - }else{ - Tile target = tile.target(); - Array removals = target.getLinkedTiles(tempTiles); - for(Tile toremove : removals){ - //note that setting a new block automatically unlinks it - if(toremove != null) toremove.setBlock(Blocks.air); - } - } - } + endMapLoad(); + } - /**Raycast, but with world coordinates.*/ - public GridPoint2 raycastWorld(float x, float y, float x2, float y2){ - return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize), - Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize)); - } - - /**Input is in block coordinates, not world coordinates. - * @return null if no collisions found, block position otherwise.*/ - public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){ - int x0 = x0f; - int y0 = y0f; - int dx = Math.abs(x1 - x0); - int dy = Math.abs(y1 - y0); + public int getSeed(){ + return seed; + } - int sx = x0 < x1 ? 1 : -1; - int sy = y0 < y1 ? 1 : -1; + public void notifyChanged(Tile tile){ + if(!generating){ + threads.runDelay(() -> Events.fire(TileChangeEvent.class, tile)); + } + } - int err = dx - dy; - int e2; - while(true){ + public void removeBlock(Tile tile){ + if(!tile.block().isMultiblock() && !tile.isLinked()){ + tile.setBlock(Blocks.air); + }else{ + Tile target = tile.target(); + Array removals = target.getLinkedTiles(tempTiles); + for(Tile toremove : removals){ + //note that setting a new block automatically unlinks it + if(toremove != null) toremove.setBlock(Blocks.air); + } + } + } - if(!passable(x0, y0)){ - return Tmp.g1.set(x0, y0); - } - if(x0 == x1 && y0 == y1) break; + public void setBlock(Tile tile, Block block, Team team){ + tile.setBlock(block); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; - e2 = 2 * err; - if(e2 > -dy){ - err = err - dy; - x0 = x0 + sx; - } + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = dx + offsetx + tile.x; + int worldy = dy + offsety + tile.y; + if(!(worldx == tile.x && worldy == tile.y)){ + Tile toplace = world.tile(worldx, worldy); + if(toplace != null){ + toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety)); + toplace.setTeam(team); + } + } + } + } + } + } - if(e2 < dx){ - err = err + dx; - y0 = y0 + sy; - } - } - return null; - } + /** + * Raycast, but with world coordinates. + */ + public GridPoint2 raycastWorld(float x, float y, float x2, float y2){ + return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize), + Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize)); + } - public void raycastEach(int x0f, int y0f, int x1, int y1, Raycaster cons){ - int x0 = x0f; - int y0 = y0f; - int dx = Math.abs(x1 - x0); - int dy = Math.abs(y1 - y0); + /** + * Input is in block coordinates, not world coordinates. + * + * @return null if no collisions found, block position otherwise. + */ + public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){ + int x0 = x0f; + int y0 = y0f; + int dx = Math.abs(x1 - x0); + int dy = Math.abs(y1 - y0); - int sx = x0 < x1 ? 1 : -1; - int sy = y0 < y1 ? 1 : -1; + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; - int err = dx - dy; - int e2; - while(true){ + int err = dx - dy; + int e2; + while(true){ - if(cons.accept(x0, y0)) break; - if(x0 == x1 && y0 == y1) break; + if(!passable(x0, y0)){ + return Tmp.g1.set(x0, y0); + } + if(x0 == x1 && y0 == y1) break; - e2 = 2 * err; - if(e2 > -dy){ - err = err - dy; - x0 = x0 + sx; - } + e2 = 2 * err; + if(e2 > -dy){ + err = err - dy; + x0 = x0 + sx; + } - if(e2 < dx){ - err = err + dx; - y0 = y0 + sy; - } - } - } + if(e2 < dx){ + err = err + dx; + y0 = y0 + sy; + } + } + return null; + } - public interface Raycaster{ - boolean accept(int x, int y); - } + public void raycastEach(int x0f, int y0f, int x1, int y1, Raycaster cons){ + int x0 = x0f; + int y0 = y0f; + int dx = Math.abs(x1 - x0); + int dy = Math.abs(y1 - y0); + + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + + int err = dx - dy; + int e2; + while(true){ + + if(cons.accept(x0, y0)) break; + if(x0 == x1 && y0 == y1) break; + + e2 = 2 * err; + if(e2 > -dy){ + err = err - dy; + x0 = x0 + sx; + } + + if(e2 < dx){ + err = err + dx; + y0 = y0 + sy; + } + } + } + + public interface Raycaster{ + boolean accept(int x, int y); + } } diff --git a/core/src/io/anuke/mindustry/editor/DrawOperation.java b/core/src/io/anuke/mindustry/editor/DrawOperation.java index 56fad5c41d..421a34bd6c 100755 --- a/core/src/io/anuke/mindustry/editor/DrawOperation.java +++ b/core/src/io/anuke/mindustry/editor/DrawOperation.java @@ -7,60 +7,66 @@ import io.anuke.mindustry.io.MapTileData.TileDataMarker; import io.anuke.ucore.util.Bits; public class DrawOperation{ - /**Data to apply operation to.*/ - private MapTileData data; - /**List of per-tile operations that occurred.*/ - private Array operations = new Array<>(); - /**Checks for duplicate operations, useful for brushes.*/ - private IntSet checks = new IntSet(); + /** + * Data to apply operation to. + */ + private MapTileData data; + /** + * List of per-tile operations that occurred. + */ + private Array operations = new Array<>(); + /** + * Checks for duplicate operations, useful for brushes. + */ + private IntSet checks = new IntSet(); - public DrawOperation(MapTileData data){ - this.data = data; - } + public DrawOperation(MapTileData data){ + this.data = data; + } - public boolean isEmpty(){ - return operations.size == 0; - } + public boolean isEmpty(){ + return operations.size == 0; + } - public boolean checkDuplicate(short x, short y){ - int i = Bits.packInt(x, y); - if(checks.contains(i)) return true; + public boolean checkDuplicate(short x, short y){ + int i = Bits.packInt(x, y); + if(checks.contains(i)) return true; - checks.add(i); - return false; - } + checks.add(i); + return false; + } - public void addOperation(TileOperation op){ - operations.add(op); - } + public void addOperation(TileOperation op){ + operations.add(op); + } - public void undo(MapEditor editor) { - for(int i = operations.size - 1; i >= 0; i --){ - TileOperation op = operations.get(i); - data.position(op.x, op.y); - data.write(op.from); - editor.renderer().updatePoint(op.x, op.y); - } - } + public void undo(MapEditor editor){ + for(int i = operations.size - 1; i >= 0; i--){ + TileOperation op = operations.get(i); + data.position(op.x, op.y); + data.write(op.from); + editor.renderer().updatePoint(op.x, op.y); + } + } - public void redo(MapEditor editor) { - for(TileOperation op : operations){ - data.position(op.x, op.y); - data.write(op.to); - editor.renderer().updatePoint(op.x, op.y); - } - } + public void redo(MapEditor editor){ + for(TileOperation op : operations){ + data.position(op.x, op.y); + data.write(op.to); + editor.renderer().updatePoint(op.x, op.y); + } + } - public static class TileOperation{ - public short x, y; - public TileDataMarker from; - public TileDataMarker to; + public static class TileOperation{ + public short x, y; + public TileDataMarker from; + public TileDataMarker to; - public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to) { - this.x = x; - this.y = y; - this.from = from; - this.to = to; - } - } + public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to){ + this.x = x; + this.y = y; + this.from = from; + this.to = to; + } + } } diff --git a/core/src/io/anuke/mindustry/editor/EditorTool.java b/core/src/io/anuke/mindustry/editor/EditorTool.java index c1bfe98750..70c69897e1 100644 --- a/core/src/io/anuke/mindustry/editor/EditorTool.java +++ b/core/src/io/anuke/mindustry/editor/EditorTool.java @@ -12,132 +12,132 @@ import io.anuke.ucore.util.Bits; import static io.anuke.mindustry.Vars.ui; public enum EditorTool{ - pick{ - public void touched(MapEditor editor, int x, int y){ - byte bf = editor.getMap().read(x, y, DataPosition.floor); - byte bw = editor.getMap().read(x, y, DataPosition.wall); - byte link = editor.getMap().read(x, y, DataPosition.link); + pick{ + public void touched(MapEditor editor, int x, int y){ + byte bf = editor.getMap().read(x, y, DataPosition.floor); + byte bw = editor.getMap().read(x, y, DataPosition.wall); + byte link = editor.getMap().read(x, y, DataPosition.link); - if(link != 0){ - x -= (Bits.getLeftByte(link) - 8); - y -= (Bits.getRightByte(link) - 8); - bf = editor.getMap().read(x, y, DataPosition.floor); - bw = editor.getMap().read(x, y, DataPosition.wall); - } + if(link != 0){ + x -= (Bits.getLeftByte(link) - 8); + y -= (Bits.getRightByte(link) - 8); + bf = editor.getMap().read(x, y, DataPosition.floor); + bw = editor.getMap().read(x, y, DataPosition.wall); + } - Block block = Block.getByID(bw == 0 ? bf : bw); - editor.setDrawBlock(block); - ui.editor.updateSelectedBlock(); - } - }, - pencil{ - { - edit = true; - draggable = true; - } + Block block = Block.getByID(bw == 0 ? bf : bw); + editor.setDrawBlock(block); + ui.editor.updateSelectedBlock(); + } + }, + pencil{ + { + edit = true; + draggable = true; + } - @Override - public void touched(MapEditor editor, int x, int y){ - editor.draw(x, y); - } - }, - eraser{ - { - edit = true; - draggable = true; - } + @Override + public void touched(MapEditor editor, int x, int y){ + editor.draw(x, y); + } + }, + eraser{ + { + edit = true; + draggable = true; + } - @Override - public void touched(MapEditor editor, int x, int y){ - editor.draw(x, y, Blocks.air); - } - }, - elevation{ - { - edit = true; - draggable = true; - } + @Override + public void touched(MapEditor editor, int x, int y){ + editor.draw(x, y, Blocks.air); + } + }, + elevation{ + { + edit = true; + draggable = true; + } - @Override - public void touched(MapEditor editor, int x, int y){ - editor.elevate(x, y); - } - }, - line{ - { + @Override + public void touched(MapEditor editor, int x, int y){ + editor.elevate(x, y); + } + }, + line{ + { - } - }, - fill{ - { - edit = true; - } - - public void touched(MapEditor editor, int x, int y){ - if(editor.getDrawBlock().isMultiblock()){ - //don't fill multiblocks, thanks - pencil.touched(editor, x, y); - return; - } + } + }, + fill{ + { + edit = true; + } - boolean floor = editor.getDrawBlock() instanceof Floor; + public void touched(MapEditor editor, int x, int y){ + if(editor.getDrawBlock().isMultiblock()){ + //don't fill multiblocks, thanks + pencil.touched(editor, x, y); + return; + } - byte bf = editor.getMap().read(x, y, DataPosition.floor); - byte bw = editor.getMap().read(x, y, DataPosition.wall); - boolean synth = editor.getDrawBlock().synthetic(); - byte brt = Bits.packByte((byte)editor.getDrawRotation(), (byte)editor.getDrawTeam().ordinal()); + boolean floor = editor.getDrawBlock() instanceof Floor; - byte dest = floor ? bf: bw; - byte draw = (byte)editor.getDrawBlock().id; + byte bf = editor.getMap().read(x, y, DataPosition.floor); + byte bw = editor.getMap().read(x, y, DataPosition.wall); + boolean synth = editor.getDrawBlock().synthetic(); + byte brt = Bits.packByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal()); - int width = editor.getMap().width(); - int height = editor.getMap().height(); + byte dest = floor ? bf : bw; + byte draw = (byte) editor.getDrawBlock().id; - IntSet set = new IntSet(); - IntArray points = new IntArray(); - points.add(asInt(x, y, editor.getMap().width())); + int width = editor.getMap().width(); + int height = editor.getMap().height(); - while(points.size != 0){ - int pos = points.pop(); - int px = pos % width; - int py = pos / width; - set.add(pos); + IntSet set = new IntSet(); + IntArray points = new IntArray(); + points.add(asInt(x, y, editor.getMap().width())); - byte nbf = editor.getMap().read(px, py, DataPosition.floor); - byte nbw = editor.getMap().read(px, py, DataPosition.wall); + while(points.size != 0){ + int pos = points.pop(); + int px = pos % width; + int py = pos / width; + set.add(pos); - if((floor ? nbf : nbw) == dest){ - TileDataMarker prev = editor.getPrev(px, py, false); + byte nbf = editor.getMap().read(px, py, DataPosition.floor); + byte nbw = editor.getMap().read(px, py, DataPosition.wall); - if(floor) { - editor.getMap().write(px, py, DataPosition.floor, draw); - }else { - editor.getMap().write(px, py, DataPosition.wall, draw); - } + if((floor ? nbf : nbw) == dest){ + TileDataMarker prev = editor.getPrev(px, py, false); - if(synth){ - editor.getMap().write(px, py, DataPosition.rotationTeam, brt); - } + if(floor){ + editor.getMap().write(px, py, DataPosition.floor, draw); + }else{ + editor.getMap().write(px, py, DataPosition.wall, draw); + } - if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width)); - if(py > 0 && !set.contains(asInt(px, py - 1, width))) points.add(asInt(px, py - 1, width)); - if(px < width - 1 && !set.contains(asInt(px + 1, py, width))) points.add(asInt(px + 1, py, width)); - if(py < height - 1 && !set.contains(asInt(px, py + 1, width))) points.add(asInt(px, py + 1, width)); + if(synth){ + editor.getMap().write(px, py, DataPosition.rotationTeam, brt); + } - editor.onWrite(px, py, prev); - } - } - } - - int asInt(int x, int y, int width){ - return x+y*width; - } - }, - zoom; + if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width)); + if(py > 0 && !set.contains(asInt(px, py - 1, width))) points.add(asInt(px, py - 1, width)); + if(px < width - 1 && !set.contains(asInt(px + 1, py, width))) points.add(asInt(px + 1, py, width)); + if(py < height - 1 && !set.contains(asInt(px, py + 1, width))) points.add(asInt(px, py + 1, width)); - boolean edit, draggable; - - public void touched(MapEditor editor, int x, int y){ - - } + editor.onWrite(px, py, prev); + } + } + } + + int asInt(int x, int y, int width){ + return x + y * width; + } + }, + zoom; + + boolean edit, draggable; + + public void touched(MapEditor editor, int x, int y){ + + } } diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index 441c077f09..9d7c2fc44e 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -14,265 +14,267 @@ import io.anuke.ucore.util.Bits; import io.anuke.ucore.util.Mathf; public class MapEditor{ - public static final int minMapSize = 128, maxMapSize = 512; - public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15}; - - private MapTileData map; - private ObjectMap tags = new ObjectMap<>(); - private MapRenderer renderer = new MapRenderer(this); + public static final int minMapSize = 128, maxMapSize = 512; + public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15}; - private int brushSize = 1; - private byte elevation; - private int rotation; - private Block drawBlock = Blocks.stone; - private Team drawTeam = Team.none; - - public MapEditor(){ + private MapTileData map; + private ObjectMap tags = new ObjectMap<>(); + private MapRenderer renderer = new MapRenderer(this); - } - - public MapTileData getMap(){ - return map; - } + private int brushSize = 1; + private byte elevation; + private int rotation; + private Block drawBlock = Blocks.stone; + private Team drawTeam = Team.none; - public ObjectMap getTags() { - return tags; - } + public MapEditor(){ - public void beginEdit(MapTileData map, ObjectMap tags){ - this.map = map; - this.brushSize = 1; - this.tags = tags; + } - for (int x = 0; x < map.width(); x++) { - for (int y = 0; y < map.height(); y++) { - map.write(x, y, DataPosition.floor, (byte)Blocks.stone.id); - } - } + public MapTileData getMap(){ + return map; + } - drawBlock = Blocks.stone; - renderer.resize(map.width(), map.height()); - } + public ObjectMap getTags(){ + return tags; + } - public void setDrawElevation(int elevation){ - this.elevation = (byte)elevation; - } + public void beginEdit(MapTileData map, ObjectMap tags, boolean clear){ + this.map = map; + this.brushSize = 1; + this.tags = tags; - public byte getDrawElevation(){ - return elevation; - } + if(clear){ + for(int x = 0; x < map.width(); x++){ + for(int y = 0; y < map.height(); y++){ + map.write(x, y, DataPosition.floor, (byte) Blocks.stone.id); + } + } + } - public int getDrawRotation(){ - return rotation; - } + drawBlock = Blocks.stone; + renderer.resize(map.width(), map.height()); + } - public void setDrawRotation(int rotation){ - this.rotation = rotation; - } + public byte getDrawElevation(){ + return elevation; + } - public void setDrawTeam(Team team){ - this.drawTeam = team; - } + public void setDrawElevation(int elevation){ + this.elevation = (byte) elevation; + } - public Team getDrawTeam() { - return drawTeam; - } + public int getDrawRotation(){ + return rotation; + } - public Block getDrawBlock(){ - return drawBlock; - } - - public void setDrawBlock(Block block){ - this.drawBlock = block; - } - - public void setBrushSize(int size){ - this.brushSize = size; - } + public void setDrawRotation(int rotation){ + this.rotation = rotation; + } - public int getBrushSize() { - return brushSize; - } + public Team getDrawTeam(){ + return drawTeam; + } - public void draw(int x, int y){ - draw(x, y, drawBlock); - } + public void setDrawTeam(Team team){ + this.drawTeam = team; + } - public void draw(int x, int y, Block drawBlock){ - if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){ - return; - } + public Block getDrawBlock(){ + return drawBlock; + } - byte writeID = (byte)drawBlock.id; - byte partID = (byte)Blocks.blockpart.id; - byte rotationTeam = Bits.packByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0); + public void setDrawBlock(Block block){ + this.drawBlock = block; + } - boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air; + public int getBrushSize(){ + return brushSize; + } - if(drawBlock.isMultiblock()) { + public void setBrushSize(int size){ + this.brushSize = size; + } - int offsetx = -(drawBlock.size - 1) / 2; - int offsety = -(drawBlock.size - 1) / 2; + public void draw(int x, int y){ + draw(x, y, drawBlock); + } - for(int i = 0; i < 2; i ++){ - for (int dx = 0; dx < drawBlock.size; dx++) { - for (int dy = 0; dy < drawBlock.size; dy++) { - int worldx = dx + offsetx + x; - int worldy = dy + offsety + y; + public void draw(int x, int y, Block drawBlock){ + if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){ + return; + } - if (Mathf.inBounds(worldx, worldy, map.width(), map.height())) { - TileDataMarker prev = getPrev(worldx, worldy, false); + byte writeID = (byte) drawBlock.id; + byte partID = (byte) Blocks.blockpart.id; + byte rotationTeam = Bits.packByte(drawBlock.rotate ? (byte) rotation : 0, drawBlock.synthetic() ? (byte) drawTeam.ordinal() : 0); - if(i == 1) { - map.write(worldx, worldy, DataPosition.wall, partID); - map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam); - map.write(worldx, worldy, DataPosition.link, Bits.packByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8))); - }else{ - byte link = map.read(worldx, worldy, DataPosition.link); - byte block = map.read(worldx, worldy, DataPosition.wall); + boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air; - if (link != 0) { - removeLinked(worldx - (Bits.getLeftByte(link) - 8), worldy - (Bits.getRightByte(link) - 8)); - }else if(Block.getByID(block).isMultiblock()){ - removeLinked(worldx, worldy); - } - } + if(drawBlock.isMultiblock()){ - onWrite(worldx, worldy, prev); - } - } - } - } + int offsetx = -(drawBlock.size - 1) / 2; + int offsety = -(drawBlock.size - 1) / 2; - TileDataMarker prev = getPrev(x, y, false); + for(int i = 0; i < 2; i++){ + for(int dx = 0; dx < drawBlock.size; dx++){ + for(int dy = 0; dy < drawBlock.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; - map.write(x, y, DataPosition.wall, writeID); - map.write(x, y, DataPosition.link, (byte)0); - map.write(x, y, DataPosition.rotationTeam, rotationTeam); + if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){ + TileDataMarker prev = getPrev(worldx, worldy, false); - onWrite(x, y, prev); - }else{ + if(i == 1){ + map.write(worldx, worldy, DataPosition.wall, partID); + map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam); + map.write(worldx, worldy, DataPosition.link, Bits.packByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8))); + }else{ + byte link = map.read(worldx, worldy, DataPosition.link); + byte block = map.read(worldx, worldy, DataPosition.wall); - for (int rx = -brushSize; rx <= brushSize; rx++) { - for (int ry = -brushSize; ry <= brushSize; ry++) { - if (Mathf.dst(rx, ry) <= brushSize - 0.5f) { - int wx = x + rx, wy = y + ry; + if(link != 0){ + removeLinked(worldx - (Bits.getLeftByte(link) - 8), worldy - (Bits.getRightByte(link) - 8)); + }else if(Block.getByID(block).isMultiblock()){ + removeLinked(worldx, worldy); + } + } - if (wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()) { - continue; - } + onWrite(worldx, worldy, prev); + } + } + } + } - TileDataMarker prev = getPrev(wx, wy, true); + TileDataMarker prev = getPrev(x, y, false); - if(!isfloor) { - byte link = map.read(wx, wy, DataPosition.link); + map.write(x, y, DataPosition.wall, writeID); + map.write(x, y, DataPosition.link, (byte) 0); + map.write(x, y, DataPosition.rotationTeam, rotationTeam); - if (link != 0) { - removeLinked(wx - (Bits.getLeftByte(link) - 8), wy - (Bits.getRightByte(link) - 8)); - } - } + onWrite(x, y, prev); + }else{ - if(isfloor){ - map.write(wx, wy, DataPosition.floor, writeID); - map.write(wx, wy, DataPosition.elevation, elevation); - }else{ - map.write(wx, wy, DataPosition.wall, writeID); - map.write(wx, wy, DataPosition.link, (byte)0); - map.write(wx, wy, DataPosition.rotationTeam, rotationTeam); - } + for(int rx = -brushSize; rx <= brushSize; rx++){ + for(int ry = -brushSize; ry <= brushSize; ry++){ + if(Mathf.dst(rx, ry) <= brushSize - 0.5f){ + int wx = x + rx, wy = y + ry; - onWrite(x + rx, y + ry, prev); - } - } - } - } - } + if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){ + continue; + } - public void elevate(int x, int y){ - if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){ - return; - } + TileDataMarker prev = getPrev(wx, wy, true); - for (int rx = -brushSize; rx <= brushSize; rx++) { - for (int ry = -brushSize; ry <= brushSize; ry++) { - if (Mathf.dst(rx, ry) <= brushSize - 0.5f) { - int wx = x + rx, wy = y + ry; + if(!isfloor){ + byte link = map.read(wx, wy, DataPosition.link); - if (wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()) { - continue; - } + if(link != 0){ + removeLinked(wx - (Bits.getLeftByte(link) - 8), wy - (Bits.getRightByte(link) - 8)); + } + } - TileDataMarker prev = getPrev(wx, wy, true); + if(isfloor){ + map.write(wx, wy, DataPosition.floor, writeID); + map.write(wx, wy, DataPosition.elevation, elevation); + }else{ + map.write(wx, wy, DataPosition.wall, writeID); + map.write(wx, wy, DataPosition.link, (byte) 0); + map.write(wx, wy, DataPosition.rotationTeam, rotationTeam); + } - map.write(wx, wy, DataPosition.elevation, elevation); + onWrite(x + rx, y + ry, prev); + } + } + } + } + } - onWrite(x + rx, y + ry, prev); - } - } - } - } + public void elevate(int x, int y){ + if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){ + return; + } - private void removeLinked(int x, int y){ - Block block = Block.getByID(map.read(x, y, DataPosition.wall)); + for(int rx = -brushSize; rx <= brushSize; rx++){ + for(int ry = -brushSize; ry <= brushSize; ry++){ + if(Mathf.dst(rx, ry) <= brushSize - 0.5f){ + int wx = x + rx, wy = y + ry; - int offsetx = -(block.size-1)/2; - int offsety = -(block.size-1)/2; - for(int dx = 0; dx < block.size; dx ++){ - for(int dy = 0; dy < block.size; dy ++){ - int worldx = x + dx + offsetx, worldy = y + dy + offsety; - if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){ - TileDataMarker prev = getPrev(worldx, worldy, false); + if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){ + continue; + } - map.write(worldx, worldy, DataPosition.link, (byte)0); - map.write(worldx, worldy, DataPosition.rotationTeam, (byte)0); - map.write(worldx, worldy, DataPosition.wall, (byte)0); + TileDataMarker prev = getPrev(wx, wy, true); - onWrite(worldx, worldy, prev); - } - } - } - } + map.write(wx, wy, DataPosition.elevation, elevation); - boolean checkDupes(int x, int y){ - return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y); - } + onWrite(x + rx, y + ry, prev); + } + } + } + } - void onWrite(int x, int y, TileDataMarker previous){ - if(previous == null){ - renderer.updatePoint(x, y); - return; - } + private void removeLinked(int x, int y){ + Block block = Block.getByID(map.read(x, y, DataPosition.wall)); - TileDataMarker current = map.new TileDataMarker(); - map.position(x, y); - map.read(current); + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + int worldx = x + dx + offsetx, worldy = y + dy + offsety; + if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){ + TileDataMarker prev = getPrev(worldx, worldy, false); - Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current)); - renderer.updatePoint(x, y); - } + map.write(worldx, worldy, DataPosition.link, (byte) 0); + map.write(worldx, worldy, DataPosition.rotationTeam, (byte) 0); + map.write(worldx, worldy, DataPosition.wall, (byte) 0); - TileDataMarker getPrev(int x, int y, boolean checkDupes){ - if(checkDupes && checkDupes(x, y)){ - return null; - }else{ - TileDataMarker marker = map.newDataMarker(); - map.position(x, y); - map.read(marker); - return marker; - } - } + onWrite(worldx, worldy, prev); + } + } + } + } - public MapRenderer renderer() { - return renderer; - } + boolean checkDupes(int x, int y){ + return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y); + } - public void resize(int width, int height){ - map = new MapTileData(width, height); - for (int x = 0; x < map.width(); x++) { - for (int y = 0; y < map.height(); y++) { - map.write(x, y, DataPosition.floor, (byte)Blocks.stone.id); - } - } - renderer.resize(width, height); - } + void onWrite(int x, int y, TileDataMarker previous){ + if(previous == null){ + renderer.updatePoint(x, y); + return; + } + + TileDataMarker current = map.new TileDataMarker(); + map.position(x, y); + map.read(current); + + Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current)); + renderer.updatePoint(x, y); + } + + TileDataMarker getPrev(int x, int y, boolean checkDupes){ + if(checkDupes && checkDupes(x, y)){ + return null; + }else{ + TileDataMarker marker = map.newDataMarker(); + map.position(x, y); + map.read(marker); + return marker; + } + } + + public MapRenderer renderer(){ + return renderer; + } + + public void resize(int width, int height){ + map = new MapTileData(width, height); + for(int x = 0; x < map.width(); x++){ + for(int y = 0; y < map.height(); y++){ + map.write(x, y, DataPosition.floor, (byte) Blocks.stone.id); + } + } + renderer.resize(width, height); + } } diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index d8624f7ef2..f004d59c63 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -3,7 +3,6 @@ package io.anuke.mindustry.editor; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; @@ -26,7 +25,6 @@ import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.function.Listenable; import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.graphics.Pixmaps; import io.anuke.ucore.input.Input; import io.anuke.ucore.scene.actions.Actions; import io.anuke.ucore.scene.builders.build; @@ -50,82 +48,82 @@ import java.io.InputStream; import static io.anuke.mindustry.Vars.*; public class MapEditorDialog extends Dialog implements Disposable{ - private MapEditor editor; - private MapView view; - private MapInfoDialog infoDialog; - private MapLoadDialog loadDialog; - private MapResizeDialog resizeDialog; - private ScrollPane pane; - private FloatingDialog menu; - private boolean saved = false; - private boolean shownWithMap = false; - - private ButtonGroup blockgroup; - - public MapEditorDialog(){ - super("$text.mapeditor", "dialog"); + private MapEditor editor; + private MapView view; + private MapInfoDialog infoDialog; + private MapLoadDialog loadDialog; + private MapResizeDialog resizeDialog; + private ScrollPane pane; + private FloatingDialog menu; + private boolean saved = false; + private boolean shownWithMap = false; - editor = new MapEditor(); - view = new MapView(editor); + private ButtonGroup blockgroup; - infoDialog = new MapInfoDialog(editor); + public MapEditorDialog(){ + super("$text.mapeditor", "dialog"); - menu = new FloatingDialog("$text.menu"); - menu.addCloseButton(); + editor = new MapEditor(); + view = new MapView(editor); - float isize = 16*2f; - float swidth = 180f; + infoDialog = new MapInfoDialog(editor); - menu.content().table(t -> { - t.defaults().size(swidth, 60f).padBottom(5).padRight(5).padLeft(5); + menu = new FloatingDialog("$text.menu"); + menu.addCloseButton(); - t.addImageTextButton("$text.editor.savemap", "icon-floppy-16", isize, this::save).size(swidth*2f + 10, 60f).colspan(2); + float isize = 16 * 2f; + float swidth = 180f; - t.row(); + menu.content().table(t -> { + t.defaults().size(swidth, 60f).padBottom(5).padRight(5).padLeft(5); - t.addImageTextButton("$text.editor.mapinfo", "icon-pencil", isize, () -> { - infoDialog.show(); - menu.hide(); - }); + t.addImageTextButton("$text.editor.savemap", "icon-floppy-16", isize, this::save).size(swidth * 2f + 10, 60f).colspan(2); - t.addImageTextButton("$text.editor.resize", "icon-resize", isize, () -> { - resizeDialog.show(); - menu.hide(); - }); + t.row(); - t.row(); + t.addImageTextButton("$text.editor.mapinfo", "icon-pencil", isize, () -> { + infoDialog.show(); + menu.hide(); + }); - t.addImageTextButton("$text.editor.import", "icon-load-map", isize, () -> - createDialog("$text.editor.import", - "$text.editor.importmap", "$text.editor.importmap.description", "icon-load-map", (Listenable)loadDialog::show, - "$text.editor.importfile", "$text.editor.importfile.description", "icon-file", (Listenable)() -> { - Platform.instance.showFileChooser("$text.loadimage", "Map Files", file -> { - ui.loadAnd(() -> { - try{ - DataInputStream stream = new DataInputStream(file.read()); + t.addImageTextButton("$text.editor.resize", "icon-resize", isize, () -> { + resizeDialog.show(); + menu.hide(); + }); - MapMeta meta = MapIO.readMapMeta(stream); - MapTileData data = MapIO.readTileData(stream, meta, false); + t.row(); - editor.beginEdit(data, meta.tags); - view.clearStack(); - }catch (Exception e){ - ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); - Log.err(e); - } - }); - }, true, mapExtension); - }, + t.addImageTextButton("$text.editor.import", "icon-load-map", isize, () -> + createDialog("$text.editor.import", + "$text.editor.importmap", "$text.editor.importmap.description", "icon-load-map", (Listenable) loadDialog::show, + "$text.editor.importfile", "$text.editor.importfile.description", "icon-file", (Listenable) () -> { + Platform.instance.showFileChooser("$text.loadimage", "Map Files", file -> { + ui.loadAnd(() -> { + try{ + DataInputStream stream = new DataInputStream(file.read()); + + MapMeta meta = MapIO.readMapMeta(stream); + MapTileData data = MapIO.readTileData(stream, meta, false); + + editor.beginEdit(data, meta.tags, false); + view.clearStack(); + }catch(Exception e){ + ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); + Log.err(e); + } + }); + }, true, mapExtension); + }/*, "$text.editor.importimage", "$text.editor.importimage.description", "icon-file-image", (Listenable)() -> { if(gwt){ - ui.showError("text.web.unsupported"); + ui.showError("$text.web.unsupported"); }else { Platform.instance.showFileChooser("$text.loadimage", "Image Files", file -> { ui.loadAnd(() -> { try{ MapTileData data = MapIO.readPixmap(new Pixmap(file)); - editor.beginEdit(data, editor.getTags()); + editor.beginEdit(data, editor.getTags(), false); view.clearStack(); }catch (Exception e){ ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); @@ -134,42 +132,42 @@ public class MapEditorDialog extends Dialog implements Disposable{ }); }, true, "png"); } - })); + }*/)); - t.addImageTextButton("$text.editor.export", "icon-save-map", isize, () -> createDialog("$text.editor.export", - "$text.editor.exportfile", "$text.editor.exportfile.description", "icon-file", (Listenable)() -> { - if(!gwt) { - Platform.instance.showFileChooser("$text.saveimage", "Map Files", file -> { - file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension); - FileHandle result = file; - ui.loadAnd(() -> { + t.addImageTextButton("$text.editor.export", "icon-save-map", isize, () -> createDialog("$text.editor.export", + "$text.editor.exportfile", "$text.editor.exportfile.description", "icon-file", (Listenable) () -> { + if(!gwt){ + Platform.instance.showFileChooser("$text.saveimage", "Map Files", file -> { + file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension); + FileHandle result = file; + ui.loadAnd(() -> { - try { - if (!editor.getTags().containsKey("name")) { - editor.getTags().put("name", result.nameWithoutExtension()); - } - MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap()); - } catch (Exception e) { - ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false))); - Log.err(e); - } - }); - }, false, mapExtension); - }else{ - try { - ByteArrayOutputStream ba = new ByteArrayOutputStream(); - MapIO.writeMap(ba, editor.getTags(), editor.getMap()); - Platform.instance.downloadFile(editor.getTags().get("name", "unknown") + "." + mapExtension, ba.toByteArray()); - }catch (IOException e){ - ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false))); - Log.err(e); - } - } - }, + try{ + if(!editor.getTags().containsKey("name")){ + editor.getTags().put("name", result.nameWithoutExtension()); + } + MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap()); + }catch(Exception e){ + ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false))); + Log.err(e); + } + }); + }, false, mapExtension); + }else{ + try{ + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + MapIO.writeMap(ba, editor.getTags(), editor.getMap()); + Platform.instance.downloadFile(editor.getTags().get("name", "unknown") + "." + mapExtension, ba.toByteArray()); + }catch(IOException e){ + ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false))); + Log.err(e); + } + } + }/*, "$text.editor.exportimage", "$text.editor.exportimage.description", "icon-file-image", (Listenable)() -> { if(gwt){ - ui.showError("text.web.unsupported"); - }else { + ui.showError("$text.web.unsupported"); + }else{ Platform.instance.showFileChooser("$text.saveimage", "Image Files", file -> { file = file.parent().child(file.nameWithoutExtension() + ".png"); FileHandle result = file; @@ -183,442 +181,443 @@ public class MapEditorDialog extends Dialog implements Disposable{ }); }, false, "png"); } - })); - - t.row(); - - t.row(); - }); - - menu.content().row(); - - menu.content().addImageTextButton("$text.quit", "icon-back", isize, () -> { - tryExit(); - menu.hide(); - }).padTop(-5).size(swidth*2f + 10, 60f); - - resizeDialog = new MapResizeDialog(editor, (x, y) -> { - if(!(editor.getMap().width() == x && editor.getMap().height() == y)){ - ui.loadAnd(() -> { - editor.resize(x, y); - view.clearStack(); - }); - } - }); - - loadDialog = new MapLoadDialog(map -> { - - ui.loadAnd(() -> { - try (DataInputStream stream = new DataInputStream(map.stream.get())){ - MapMeta meta = MapIO.readMapMeta(stream); - MapTileData data = MapIO.readTileData(stream, meta, false); - - editor.beginEdit(data, meta.tags); - view.clearStack(); - }catch (IOException e){ - ui.showError(Bundles.format("text.editor.errormapload", Strings.parseException(e, false))); - Log.err(e); - } - }); - }); - - setFillParent(true); - - clearChildren(); - margin(0); - build.begin(this); - build(); - build.end(); - - update(() -> { - if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this) { - return; - } - - Vector2 v = pane.stageToLocalCoordinates(Graphics.mouse()); - - if(v.x >= 0 && v.y >= 0 && v.x <= pane.getWidth() && v.y <= pane.getHeight()){ - Core.scene.setScrollFocus(pane); - }else{ - Core.scene.setScrollFocus(null); - } - - if(Core.scene != null && Core.scene.getKeyboardFocus() == this){ - doInput(); - } - }); - - shown(() -> { - saved = true; - Platform.instance.beginForceLandscape(); - view.clearStack(); - Core.scene.setScrollFocus(view); - if(!shownWithMap){ - editor.beginEdit(new MapTileData(256, 256), new ObjectMap<>()); - } - shownWithMap = false; - - Timers.runTask(10f, Platform.instance::updateRPC); - }); - - hidden(() -> { - Platform.instance.updateRPC(); - Platform.instance.endForceLandscape(); - }); - } - - private void save(){ - String name = editor.getTags().get("name", ""); - - if(name.isEmpty()){ - ui.showError("$text.editor.save.noname"); - }else{ - Map map = world.maps().getByName(name); - if(map != null && !map.custom){ - ui.showError("$text.editor.save.overwrite"); - }else{ - world.maps().saveMap(name, editor.getMap(), editor.getTags()); - ui.showInfoFade("$text.editor.saved"); - } - } - - menu.hide(); - saved = true; - } - - /**Argument format: - * 0) button name - * 1) description - * 2) icon name - * 3) listener */ - private FloatingDialog createDialog(String title, Object... arguments){ - FloatingDialog dialog = new FloatingDialog(title); - - float h = 90f; - - dialog.content().defaults().size(360f, h).padBottom(5).padRight(5).padLeft(5); - - for(int i = 0; i < arguments.length; i += 4){ - String name = (String)arguments[i]; - String description = (String)arguments[i + 1]; - String iconname = (String)arguments[i + 2]; - Listenable listenable = (Listenable)arguments[i + 3]; - - TextButton button = dialog.content().addButton(name, () -> { - listenable.listen(); - dialog.hide(); - menu.hide(); - }).left().get(); - - button.clearChildren(); - button.table("button", t -> { - t.addImage(iconname).size(16*3); - t.update(() -> t.background(button.getClickListener().isOver() ? "button-over" : "button")); - }).padLeft(-10).padBottom(-3).size(h); - button.table(t -> { - t.add(name).growX().wrap(); - t.row(); - t.add(description).color(Color.GRAY).growX().wrap(); - }).growX().padLeft(8); - - button.row(); - - dialog.content().row(); - } - - dialog.addCloseButton(); - dialog.show(); - - return dialog; - } - - @Override - public Dialog show(){ - return super.show(Core.scene, Actions.sequence(Actions.alpha(0f), Actions.scaleTo(1f, 1f), Actions.fadeIn(0.3f))); - } - - @Override - public void dispose(){ - editor.renderer().dispose(); - } - - public void beginEditMap(InputStream is){ - ui.loadAnd(() -> { - try { - shownWithMap = true; - DataInputStream stream = new DataInputStream(is); - MapMeta meta = MapIO.readMapMeta(stream); - editor.beginEdit(MapIO.readTileData(stream, meta, false), meta.tags); - is.close(); - show(); - }catch (Exception e){ - Log.err(e); - ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); - } - }); - } - - public MapView getView() { - return view; - } - - public void resetSaved(){ - saved = false; - } - - public void updateSelectedBlock(){ - Block block = editor.getDrawBlock(); - int i = 0; - for(int j = 0; j < Block.all().size; j ++){ - if(block.id == j){ - blockgroup.getButtons().get(i).setChecked(true); - break; - } - i++; - } - } - - public boolean hasPane(){ - return Core.scene.getScrollFocus() == pane || Core.scene.getKeyboardFocus() != this; - } - - public void build(){ - float amount = 10f, baseSize = 60f; - - float size = mobile ? (int)(Math.min(Gdx.graphics.getHeight(), Gdx.graphics.getWidth()) / amount / Unit.dp.scl(1f)) : - Math.min(Gdx.graphics.getDisplayMode().height / amount, baseSize); - - new table(){{ - aleft(); - - new table("button"){{ - margin(0); - Table tools = new Table(); - tools.top(); - atop(); - - ButtonGroup group = new ButtonGroup<>(); - - Consumer addTool = tool -> { - ImageButton button = new ImageButton("icon-" + tool.name(), "toggle"); - button.clicked(() -> view.setTool(tool)); - button.resizeImage(16*2f); - button.update(() -> button.setChecked(view.getTool() == tool)); - group.add(button); - if (tool == EditorTool.pencil) - button.setChecked(true); - - tools.add(button).padBottom(-5.1f); - }; - - tools.defaults().size(size, size + 4f).padBottom(-5.1f); - - //tools.addImageButton("icon-back", 16*2, () -> tryExit()); - - tools.addImageButton("icon-menu-large", 16*2f, menu::show); - - ImageButton grid = tools.addImageButton("icon-grid", "toggle", 16*2f, () -> view.setGrid(!view.isGrid())).get(); + }*/)); + + t.row(); + + t.row(); + }); + + menu.content().row(); + + menu.content().addImageTextButton("$text.quit", "icon-back", isize, () -> { + tryExit(); + menu.hide(); + }).padTop(-5).size(swidth * 2f + 10, 60f); + + resizeDialog = new MapResizeDialog(editor, (x, y) -> { + if(!(editor.getMap().width() == x && editor.getMap().height() == y)){ + ui.loadAnd(() -> { + editor.resize(x, y); + view.clearStack(); + }); + } + }); + + loadDialog = new MapLoadDialog(map -> { + + ui.loadAnd(() -> { + try(DataInputStream stream = new DataInputStream(map.stream.get())){ + MapMeta meta = MapIO.readMapMeta(stream); + MapTileData data = MapIO.readTileData(stream, meta, false); + + editor.beginEdit(data, meta.tags, false); + view.clearStack(); + }catch(IOException e){ + ui.showError(Bundles.format("text.editor.errormapload", Strings.parseException(e, false))); + Log.err(e); + } + }); + }); + + setFillParent(true); + + clearChildren(); + margin(0); + build.begin(this); + build(); + build.end(); + + update(() -> { + if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){ + return; + } + + Vector2 v = pane.stageToLocalCoordinates(Graphics.mouse()); + + if(v.x >= 0 && v.y >= 0 && v.x <= pane.getWidth() && v.y <= pane.getHeight()){ + Core.scene.setScrollFocus(pane); + }else{ + Core.scene.setScrollFocus(null); + } + + if(Core.scene != null && Core.scene.getKeyboardFocus() == this){ + doInput(); + } + }); + + shown(() -> { + saved = true; + Platform.instance.beginForceLandscape(); + view.clearStack(); + Core.scene.setScrollFocus(view); + if(!shownWithMap){ + editor.beginEdit(new MapTileData(256, 256), new ObjectMap<>(), true); + } + shownWithMap = false; + + Timers.runTask(10f, Platform.instance::updateRPC); + }); + + hidden(() -> { + Platform.instance.updateRPC(); + Platform.instance.endForceLandscape(); + }); + } + + private void save(){ + String name = editor.getTags().get("name", ""); + + if(name.isEmpty()){ + ui.showError("$text.editor.save.noname"); + }else{ + Map map = world.maps().getByName(name); + if(map != null && !map.custom){ + ui.showError("$text.editor.save.overwrite"); + }else{ + world.maps().saveMap(name, editor.getMap(), editor.getTags()); + ui.showInfoFade("$text.editor.saved"); + } + } + + menu.hide(); + saved = true; + } + + /** + * Argument format: + * 0) button name + * 1) description + * 2) icon name + * 3) listener + */ + private FloatingDialog createDialog(String title, Object... arguments){ + FloatingDialog dialog = new FloatingDialog(title); + + float h = 90f; + + dialog.content().defaults().size(360f, h).padBottom(5).padRight(5).padLeft(5); + + for(int i = 0; i < arguments.length; i += 4){ + String name = (String) arguments[i]; + String description = (String) arguments[i + 1]; + String iconname = (String) arguments[i + 2]; + Listenable listenable = (Listenable) arguments[i + 3]; + + TextButton button = dialog.content().addButton(name, () -> { + listenable.listen(); + dialog.hide(); + menu.hide(); + }).left().get(); + + button.clearChildren(); + button.table("button", t -> { + t.addImage(iconname).size(16 * 3); + t.update(() -> t.background(button.getClickListener().isOver() ? "button-over" : "button")); + }).padLeft(-10).padBottom(-3).size(h); + button.table(t -> { + t.add(name).growX().wrap(); + t.row(); + t.add(description).color(Color.GRAY).growX().wrap(); + }).growX().padLeft(8); + + button.row(); + + dialog.content().row(); + } + + dialog.addCloseButton(); + dialog.show(); + + return dialog; + } + + @Override + public Dialog show(){ + return super.show(Core.scene, Actions.sequence(Actions.alpha(0f), Actions.scaleTo(1f, 1f), Actions.fadeIn(0.3f))); + } + + @Override + public void dispose(){ + editor.renderer().dispose(); + } + + public void beginEditMap(InputStream is){ + ui.loadAnd(() -> { + try{ + shownWithMap = true; + DataInputStream stream = new DataInputStream(is); + MapMeta meta = MapIO.readMapMeta(stream); + editor.beginEdit(MapIO.readTileData(stream, meta, false), meta.tags, false); + is.close(); + show(); + }catch(Exception e){ + Log.err(e); + ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); + } + }); + } + + public MapView getView(){ + return view; + } + + public void resetSaved(){ + saved = false; + } + + public void updateSelectedBlock(){ + Block block = editor.getDrawBlock(); + for(int j = 0; j < Block.all().size; j++){ + if(block.id == j && j < blockgroup.getButtons().size){ + blockgroup.getButtons().get(j).setChecked(true); + break; + } + } + } + + public boolean hasPane(){ + return Core.scene.getScrollFocus() == pane || Core.scene.getKeyboardFocus() != this; + } - addTool.accept(EditorTool.zoom); + public void build(){ + float amount = 10f, baseSize = 60f; + + float size = mobile ? (int) (Math.min(Gdx.graphics.getHeight(), Gdx.graphics.getWidth()) / amount / Unit.dp.scl(1f)) : + Math.min(Gdx.graphics.getDisplayMode().height / amount, baseSize); + + new table(){{ + aleft(); + + new table("button"){{ + margin(0); + Table tools = new Table(); + tools.top(); + atop(); - tools.row(); + ButtonGroup group = new ButtonGroup<>(); - ImageButton undo = tools.addImageButton("icon-undo", 16*2f, () -> view.undo()).get(); - ImageButton redo = tools.addImageButton("icon-redo", 16*2f, () -> view.redo()).get(); - - addTool.accept(EditorTool.pick); - - tools.row(); - - undo.setDisabled(() -> !view.getStack().canUndo()); - redo.setDisabled(() -> !view.getStack().canRedo()); - - undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE)); - redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE)); - grid.update(() -> grid.setChecked(view.isGrid())); - - addTool.accept(EditorTool.line); - addTool.accept(EditorTool.pencil); - addTool.accept(EditorTool.eraser); - - tools.row(); - - addTool.accept(EditorTool.fill); - addTool.accept(EditorTool.elevation); - - ImageButton rotate = tools.addImageButton("icon-arrow-16", 16*2f, () -> editor.setDrawRotation((editor.getDrawRotation() + 1)%4)).get(); - rotate.getImage().update(() ->{ - rotate.getImage().setRotation(editor.getDrawRotation() * 90); - rotate.getImage().setOrigin(Align.center); - }); - - tools.row(); - - tools.table("button", t -> { - t.add("$text.editor.teams"); - }).colspan(3).height(40).width(size*3f); + Consumer addTool = tool -> { + ImageButton button = new ImageButton("icon-" + tool.name(), "toggle"); + button.clicked(() -> view.setTool(tool)); + button.resizeImage(16 * 2f); + button.update(() -> button.setChecked(view.getTool() == tool)); + group.add(button); + if(tool == EditorTool.pencil) + button.setChecked(true); - tools.row(); - - ButtonGroup teamgroup = new ButtonGroup<>(); + tools.add(button).padBottom(-5.1f); + }; - int i = 0; - - for(Team team : Team.all){ - ImageButton button = new ImageButton("white", "toggle"); - button.margin(4f, 4f, 10f, 4f); - button.getImageCell().grow(); - button.getStyle().imageUpColor = team.color; - button.clicked(() -> editor.setDrawTeam(team)); - button.update(() -> button.setChecked(editor.getDrawTeam() == team)); - teamgroup.add(button); - tools.add(button).padBottom(-5.1f); + tools.defaults().size(size, size + 4f).padBottom(-5.1f); - if(i++ % 3 == 2) tools.row(); - } + //tools.addImageButton("icon-back", 16*2, () -> tryExit()); - add(tools).top().padBottom(-6); + tools.addImageButton("icon-menu-large", 16 * 2f, menu::show); - row(); + ImageButton grid = tools.addImageButton("icon-grid", "toggle", 16 * 2f, () -> view.setGrid(!view.isGrid())).get(); - new table("button"){{ - atop(); - Slider slider = new Slider(0, MapEditor.brushSizes.length-1, 1, false); - slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int)(float)f])); - new label("brush"); - row(); - add(slider).width(size*3f-20).padTop(4f); - }}.padTop(5).growX().growY().top().end(); - - row(); - - get().table("button", t -> { - t.add("$text.editor.elevation"); - }).colspan(3).height(40).width(size*3f); + addTool.accept(EditorTool.zoom); - row(); - - get().table("button", t -> { - t.margin(0); - t.addImageButton("icon-arrow-left", 16*2f, () -> editor.setDrawElevation(editor.getDrawElevation() - 1)) - .disabled(b -> editor.getDrawElevation() <= -1).size(size); - - t.label(() -> editor.getDrawElevation() == -1 ? "$text.editor.slope" : (editor.getDrawElevation() + "")) - .size(size).get().setAlignment(Align.center, Align.center); - - t.addImageButton("icon-arrow-right", 16*2f, () -> editor.setDrawElevation(editor.getDrawElevation() + 1)) - .disabled(b -> editor.getDrawElevation() >= 127).size(size); - }).colspan(3).height(size).padTop(-5).width(size*3f); - - }}.left().growY().end(); - - - new table("button"){{ - margin(5); - marginBottom(10); - add(view).grow(); - }}.grow().end(); - - new table(){{ - - row(); - - addBlockSelection(get()); - - row(); - - }}.right().growY().end(); - }}.grow().end(); - } - - private void doInput(){ - //tool select - for(int i = 0; i < EditorTool.values().length; i ++){ - if(Inputs.keyTap(Input.valueOf("NUM_" + (i+1)))){ - view.setTool(EditorTool.values()[i]); - break; - } - } - - if(Inputs.keyTap(Input.R)){ - editor.setDrawRotation((editor.getDrawRotation() + 1)%4); - } - - if(Inputs.keyTap(Input.E)){ - editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4)); - } - - //ctrl keys (undo, redo, save) - if(UIUtils.ctrl()){ - if(Inputs.keyTap(Input.Z)){ - view.undo(); - } - - if(Inputs.keyTap(Input.Y)){ - view.redo(); - } - - if(Inputs.keyTap(Input.S)){ - save(); - } - - if(Inputs.keyTap(Input.G)){ - view.setGrid(!view.isGrid()); - } - } - } - - private void tryExit(){ - if(!saved){ - ui.showConfirm("$text.confirm", "$text.editor.unsaved", this::hide); - }else{ - hide(); - } - } - - private void addBlockSelection(Table table){ - Table content = new Table(); - pane = new ScrollPane(content, "volume"); - pane.setFadeScrollBars(false); - pane.setOverscroll(true, false); - ButtonGroup group = new ButtonGroup<>(); - blockgroup = group; - - int i = 0; - - for(Block block : Block.all()){ - TextureRegion[] regions = block.getCompactIcon(); - if((block.synthetic() && (Recipe.getByResult(block) == null || !control.database().isUnlocked(Recipe.getByResult(block)))) && !debug && block != StorageBlocks.core) continue; - - if(regions.length == 0 || regions[0] == Draw.region("jjfgj")) continue; - - Stack stack = new Stack(); - - for(TextureRegion region : regions){ - stack.add(new Image(region)); - } - - ImageButton button = new ImageButton("white", "toggle"); - button.clicked(() -> editor.setDrawBlock(block)); - button.resizeImage(8*4f); - button.getImageCell().setActor(stack); - button.addChild(stack); - button.getImage().remove(); - button.update(() -> button.setChecked(editor.getDrawBlock() == block)); - group.add(button); - content.add(button).pad(4f).size(53f, 58f); - - if(i++ % 3 == 2){ - content.row(); - } - } - - group.getButtons().get(2).setChecked(true); - - Table extra = new Table("button"); - extra.labelWrap(() -> editor.getDrawBlock().formalName).width(220f).center(); - table.add(extra).growX(); - table.row(); - table.add(pane).growY().fillX(); - } + tools.row(); + + ImageButton undo = tools.addImageButton("icon-undo", 16 * 2f, () -> view.undo()).get(); + ImageButton redo = tools.addImageButton("icon-redo", 16 * 2f, () -> view.redo()).get(); + + addTool.accept(EditorTool.pick); + + tools.row(); + + undo.setDisabled(() -> !view.getStack().canUndo()); + redo.setDisabled(() -> !view.getStack().canRedo()); + + undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE)); + redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE)); + grid.update(() -> grid.setChecked(view.isGrid())); + + addTool.accept(EditorTool.line); + addTool.accept(EditorTool.pencil); + addTool.accept(EditorTool.eraser); + + tools.row(); + + addTool.accept(EditorTool.fill); + addTool.accept(EditorTool.elevation); + + ImageButton rotate = tools.addImageButton("icon-arrow-16", 16 * 2f, () -> editor.setDrawRotation((editor.getDrawRotation() + 1) % 4)).get(); + rotate.getImage().update(() -> { + rotate.getImage().setRotation(editor.getDrawRotation() * 90); + rotate.getImage().setOrigin(Align.center); + }); + + tools.row(); + + tools.table("button", t -> { + t.add("$text.editor.teams"); + }).colspan(3).height(40).width(size * 3f); + + tools.row(); + + ButtonGroup teamgroup = new ButtonGroup<>(); + + int i = 0; + + for(Team team : Team.all){ + ImageButton button = new ImageButton("white", "toggle"); + button.margin(4f, 4f, 10f, 4f); + button.getImageCell().grow(); + button.getStyle().imageUpColor = team.color; + button.clicked(() -> editor.setDrawTeam(team)); + button.update(() -> button.setChecked(editor.getDrawTeam() == team)); + teamgroup.add(button); + tools.add(button).padBottom(-5.1f); + + if(i++ % 3 == 2) tools.row(); + } + + add(tools).top().padBottom(-6); + + row(); + + new table("button"){{ + atop(); + Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false); + slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int) (float) f])); + new label("brush"); + row(); + add(slider).width(size * 3f - 20).padTop(4f); + }}.padTop(5).growX().growY().top().end(); + + row(); + + get().table("button", t -> { + t.add("$text.editor.elevation"); + }).colspan(3).height(40).width(size * 3f); + + row(); + + get().table("button", t -> { + t.margin(0); + t.addImageButton("icon-arrow-left", 16 * 2f, () -> editor.setDrawElevation(editor.getDrawElevation() - 1)) + .disabled(b -> editor.getDrawElevation() <= -1).size(size); + + t.label(() -> editor.getDrawElevation() == -1 ? "$text.editor.slope" : (editor.getDrawElevation() + "")) + .size(size).get().setAlignment(Align.center, Align.center); + + t.addImageButton("icon-arrow-right", 16 * 2f, () -> editor.setDrawElevation(editor.getDrawElevation() + 1)) + .disabled(b -> editor.getDrawElevation() >= 127).size(size); + }).colspan(3).height(size).padTop(-5).width(size * 3f); + + }}.left().growY().end(); + + + new table("button"){{ + margin(5); + marginBottom(10); + add(view).grow(); + }}.grow().end(); + + new table(){{ + + row(); + + addBlockSelection(get()); + + row(); + + }}.right().growY().end(); + }}.grow().end(); + } + + private void doInput(){ + //tool select + for(int i = 0; i < EditorTool.values().length; i++){ + if(Inputs.keyTap(Input.valueOf("NUM_" + (i + 1)))){ + view.setTool(EditorTool.values()[i]); + break; + } + } + + if(Inputs.keyTap(Input.R)){ + editor.setDrawRotation((editor.getDrawRotation() + 1) % 4); + } + + if(Inputs.keyTap(Input.E)){ + editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4)); + } + + //ctrl keys (undo, redo, save) + if(UIUtils.ctrl()){ + if(Inputs.keyTap(Input.Z)){ + view.undo(); + } + + if(Inputs.keyTap(Input.Y)){ + view.redo(); + } + + if(Inputs.keyTap(Input.S)){ + save(); + } + + if(Inputs.keyTap(Input.G)){ + view.setGrid(!view.isGrid()); + } + } + } + + private void tryExit(){ + if(!saved){ + ui.showConfirm("$text.confirm", "$text.editor.unsaved", this::hide); + }else{ + hide(); + } + } + + private void addBlockSelection(Table table){ + Table content = new Table(); + pane = new ScrollPane(content, "volume"); + pane.setFadeScrollBars(false); + pane.setOverscroll(true, false); + ButtonGroup group = new ButtonGroup<>(); + blockgroup = group; + + int i = 0; + + for(Block block : Block.all()){ + TextureRegion[] regions = block.getCompactIcon(); + if((block.synthetic() && (Recipe.getByResult(block) == null || !control.database().isUnlocked(Recipe.getByResult(block)))) && !debug && block != StorageBlocks.core) + continue; + + if(regions.length == 0 || regions[0] == Draw.region("jjfgj")) continue; + + Stack stack = new Stack(); + + for(TextureRegion region : regions){ + stack.add(new Image(region)); + } + + ImageButton button = new ImageButton("white", "toggle"); + button.clicked(() -> editor.setDrawBlock(block)); + button.resizeImage(8 * 4f); + button.getImageCell().setActor(stack); + button.addChild(stack); + button.getImage().remove(); + button.update(() -> button.setChecked(editor.getDrawBlock() == block)); + group.add(button); + content.add(button).pad(4f).size(53f, 58f); + + if(i++ % 3 == 2){ + content.row(); + } + } + + group.getButtons().get(2).setChecked(true); + + Table extra = new Table("button"); + extra.labelWrap(() -> editor.getDrawBlock().formalName).width(220f).center(); + table.add(extra).growX(); + table.row(); + table.add(pane).growY().fillX(); + } } diff --git a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java index 52fd0eb2a3..c9c249636e 100644 --- a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java @@ -14,68 +14,68 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.world; public class MapLoadDialog extends FloatingDialog{ - private Map selected = null; + private Map selected = null; - public MapLoadDialog(Consumer loader) { - super("$text.editor.loadmap"); + public MapLoadDialog(Consumer loader){ + super("$text.editor.loadmap"); - shown(this::rebuild); - rebuild(); + shown(this::rebuild); + rebuild(); - TextButton button = new TextButton("$text.load"); - button.setDisabled(() -> selected == null); - button.clicked(() -> { - if (selected != null) { - loader.accept(selected); - hide(); - } - }); + TextButton button = new TextButton("$text.load"); + button.setDisabled(() -> selected == null); + button.clicked(() -> { + if(selected != null){ + loader.accept(selected); + hide(); + } + }); - buttons().defaults().size(200f, 50f); - buttons().addButton("$text.cancel", this::hide); - buttons().add(button); - } + buttons().defaults().size(200f, 50f); + buttons().addButton("$text.cancel", this::hide); + buttons().add(button); + } - public void rebuild(){ - content().clear(); - if(world.maps().all().size > 0){ - selected = world.maps().all().first(); - } + public void rebuild(){ + content().clear(); + if(world.maps().all().size > 0){ + selected = world.maps().all().first(); + } - ButtonGroup group = new ButtonGroup<>(); + ButtonGroup group = new ButtonGroup<>(); - int maxcol = 3; + int maxcol = 3; - int i = 0; + int i = 0; - Table table = new Table(); - table.defaults().size(200f, 90f).pad(4f); - table.margin(10f); + Table table = new Table(); + table.defaults().size(200f, 90f).pad(4f); + table.margin(10f); - ScrollPane pane = new ScrollPane(table, "horizontal"); - pane.setFadeScrollBars(false); + ScrollPane pane = new ScrollPane(table, "horizontal"); + pane.setFadeScrollBars(false); - for (Map map : world.maps().all()) { + for(Map map : world.maps().all()){ - TextButton button = new TextButton(map.getDisplayName(), "toggle"); - button.add(new BorderImage(map.texture, 2f)).size(16 * 4f); - button.getCells().reverse(); - button.clicked(() -> selected = map); - button.getLabelCell().grow().left().padLeft(5f); - group.add(button); - table.add(button); - if (++i % maxcol == 0) table.row(); - } + TextButton button = new TextButton(map.getDisplayName(), "toggle"); + button.add(new BorderImage(map.texture, 2f)).size(16 * 4f); + button.getCells().reverse(); + button.clicked(() -> selected = map); + button.getLabelCell().grow().left().padLeft(5f); + group.add(button); + table.add(button); + if(++i % maxcol == 0) table.row(); + } - if(world.maps().all().size == 0){ - pane.setStyle(Core.skin.get("clear", ScrollPaneStyle.class)); - table.add("$text.maps.none").center(); - }else { - content().add("$text.editor.loadmap"); - } + if(world.maps().all().size == 0){ + pane.setStyle(Core.skin.get("clear", ScrollPaneStyle.class)); + table.add("$text.maps.none").center(); + }else{ + content().add("$text.editor.loadmap"); + } - content().row(); - content().add(pane); - } + content().row(); + content().add(pane); + } } diff --git a/core/src/io/anuke/mindustry/editor/MapRenderer.java b/core/src/io/anuke/mindustry/editor/MapRenderer.java index 16fc993438..b86c8bf7e1 100644 --- a/core/src/io/anuke/mindustry/editor/MapRenderer.java +++ b/core/src/io/anuke/mindustry/editor/MapRenderer.java @@ -34,18 +34,18 @@ public class MapRenderer implements Disposable{ public void resize(int width, int height){ if(chunks != null){ - for(int x = 0; x < chunks.length; x ++){ - for(int y = 0; y < chunks[0].length; y ++){ + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ chunks[x][y].dispose(); } } } - chunks = new IndexedRenderer[(int)Math.ceil((float)width/chunksize)][(int)Math.ceil((float)height/chunksize )]; + chunks = new IndexedRenderer[(int) Math.ceil((float) width / chunksize)][(int) Math.ceil((float) height / chunksize)]; - for(int x = 0; x < chunks.length; x ++){ - for(int y = 0; y < chunks[0].length; y ++){ - chunks[x][y] = new IndexedRenderer(chunksize*chunksize*2); + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ + chunks[x][y] = new IndexedRenderer(chunksize * chunksize * 2); } } this.width = width; @@ -69,8 +69,8 @@ public class MapRenderer implements Disposable{ updates.addAll(delayedUpdates); delayedUpdates.clear(); - for(int x = 0; x < chunks.length; x ++){ - for(int y = 0; y < chunks[0].length; y ++){ + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ IndexedRenderer mesh = chunks[x][y]; mesh.getTransformMatrix().setToTranslation(tx, ty, 0).scl(tw / (width * tilesize), @@ -86,19 +86,19 @@ public class MapRenderer implements Disposable{ public void updatePoint(int x, int y){ //TODO spread out over multiple frames? - updates.add(x + y*width); + updates.add(x + y * width); } public void updateAll(){ - for(int x = 0; x < width; x ++){ - for(int y = 0; y < height; y ++){ + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ render(x, y); } } } private void render(int wx, int wy){ - int x = wx/chunksize, y = wy/chunksize; + int x = wx / chunksize, y = wy / chunksize; IndexedRenderer mesh = chunks[x][y]; //TileDataMarker data = editor.getMap().readAt(wx, wy); byte bf = editor.getMap().read(wx, wy, DataPosition.floor); @@ -111,19 +111,19 @@ public class MapRenderer implements Disposable{ Block floor = Block.getByID(bf); Block wall = Block.getByID(bw); - int offsetx = -(wall.size-1)/2; - int offsety = -(wall.size-1)/2; + int offsetx = -(wall.size - 1) / 2; + int offsety = -(wall.size - 1) / 2; TextureRegion region; - if(bw != 0) { + if(bw != 0){ region = wall.getEditorIcon(); - if (wall.rotate) { + if(wall.rotate){ mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region, wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize, region.getRegionWidth(), region.getRegionHeight(), rotation * 90 - 90); - } else { + }else{ mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region, wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize, region.getRegionWidth(), region.getRegionHeight()); @@ -131,16 +131,16 @@ public class MapRenderer implements Disposable{ }else{ region = floor.getEditorIcon(); - mesh.draw((wx % chunksize) + (wy % chunksize)*chunksize, region, wx * tilesize, wy * tilesize, 8, 8); + mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region, wx * tilesize, wy * tilesize, 8, 8); } boolean check = checkElevation(elev, wx, wy); - if(wall.update || wall.destructible) { + if(wall.update || wall.destructible){ mesh.setColor(team.color); region = Draw.region("block-border"); }else if(elev > 0 && check){ - mesh.setColor(tmpColor.fromHsv((360f * elev/127f * 4f) % 360f, 0.5f + (elev / 4f) % 0.5f, 1f)); + mesh.setColor(tmpColor.fromHsv((360f * elev / 127f * 4f) % 360f, 0.5f + (elev / 4f) % 0.5f, 1f)); region = Draw.region("block-elevation"); }else if(elev == -1){ region = Draw.region("block-slope"); @@ -148,8 +148,8 @@ public class MapRenderer implements Disposable{ region = Draw.region("clear"); } - mesh.draw((wx % chunksize) + (wy % chunksize)*chunksize + chunksize*chunksize, region, - wx * tilesize + offsetx*tilesize, wy * tilesize + offsety * tilesize, + mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize, region, + wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize, region.getRegionWidth(), region.getRegionHeight()); mesh.setColor(Color.WHITE); } @@ -165,19 +165,19 @@ public class MapRenderer implements Disposable{ if(value < elev){ return true; }else if(value > elev){ - delayedUpdates.add(wx + wy*width); + delayedUpdates.add(wx + wy * width); } } return false; } @Override - public void dispose() { + public void dispose(){ if(chunks == null){ return; } - for(int x = 0; x < chunks.length; x ++){ - for(int y = 0; y < chunks[0].length; y ++){ + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ if(chunks[x][y] != null){ chunks[x][y].dispose(); } diff --git a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java index 3daebbd825..a5ffc63835 100644 --- a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java @@ -9,55 +9,55 @@ import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Mathf; public class MapResizeDialog extends FloatingDialog{ - int[] validMapSizes = {200, 300, 400, 500}; - int width, height; - - public MapResizeDialog(MapEditor editor, BiConsumer cons){ - super("$text.editor.resizemap"); - shown(() -> { - content().clear(); - MapTileData data = editor.getMap(); - width = data.width(); - height = data.height(); - - Table table = new Table(); - - for(boolean w : Mathf.booleans){ - int curr = w ? data.width() : data.height(); - int idx = 0; - for(int i = 0; i < validMapSizes.length; i ++) { - if (validMapSizes[i] == curr) idx = i; - } - - table.add(w ? "$text.width": "$text.height").padRight(8f); - ButtonGroup group = new ButtonGroup<>(); - for(int i = 0; i < validMapSizes.length; i ++){ - int size = validMapSizes[i]; - TextButton button = new TextButton(size + "", "toggle"); - button.clicked(() -> { - if(w) - width = size; - else - height = size; - }); - group.add(button); - if(i == idx) button.setChecked(true); - table.add(button).size(100f, 54f).pad(2f); - } - - table.row(); - } - content().row(); - content().add(table); - - }); - - buttons().defaults().size(200f, 50f); - buttons().addButton("$text.cancel", this::hide); - buttons().addButton("$text.editor.resize", () -> { - cons.accept(width, height); - hide(); - }); - - } + int[] validMapSizes = {200, 300, 400, 500}; + int width, height; + + public MapResizeDialog(MapEditor editor, BiConsumer cons){ + super("$text.editor.resizemap"); + shown(() -> { + content().clear(); + MapTileData data = editor.getMap(); + width = data.width(); + height = data.height(); + + Table table = new Table(); + + for(boolean w : Mathf.booleans){ + int curr = w ? data.width() : data.height(); + int idx = 0; + for(int i = 0; i < validMapSizes.length; i++){ + if(validMapSizes[i] == curr) idx = i; + } + + table.add(w ? "$text.width" : "$text.height").padRight(8f); + ButtonGroup group = new ButtonGroup<>(); + for(int i = 0; i < validMapSizes.length; i++){ + int size = validMapSizes[i]; + TextButton button = new TextButton(size + "", "toggle"); + button.clicked(() -> { + if(w) + width = size; + else + height = size; + }); + group.add(button); + if(i == idx) button.setChecked(true); + table.add(button).size(100f, 54f).pad(2f); + } + + table.row(); + } + content().row(); + content().add(table); + + }); + + buttons().defaults().size(200f, 50f); + buttons().addButton("$text.cancel", this::hide); + buttons().addButton("$text.editor.resize", () -> { + cons.accept(width, height); + hide(); + }); + + } } diff --git a/core/src/io/anuke/mindustry/editor/MapSaveDialog.java b/core/src/io/anuke/mindustry/editor/MapSaveDialog.java index cc4956ef5a..c11318298b 100644 --- a/core/src/io/anuke/mindustry/editor/MapSaveDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapSaveDialog.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.editor; -import io.anuke.mindustry.io.Map; import io.anuke.mindustry.core.Platform; +import io.anuke.mindustry.io.Map; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.scene.ui.TextButton; @@ -11,65 +11,65 @@ import static io.anuke.mindustry.Vars.ui; import static io.anuke.mindustry.Vars.world; public class MapSaveDialog extends FloatingDialog{ - private TextField field; - private Consumer listener; - - public MapSaveDialog(Consumer cons){ - super("$text.editor.savemap"); - field = new TextField(); - listener = cons; - - Platform.instance.addDialog(field); - - shown(() -> { - content().clear(); - content().label(() ->{ - Map map = world.maps().getByName(field.getText()); - if(map != null){ - if(map.custom){ - return "$text.editor.overwrite"; - }else{ - return "$text.editor.failoverwrite"; - } - } - return ""; - }).colspan(2); - content().row(); - content().add("$text.editor.mapname").padRight(14f); - content().add(field).size(220f, 48f); - }); - - buttons().defaults().size(200f, 50f).pad(2f); - buttons().addButton("$text.cancel", this::hide); - - TextButton button = new TextButton("$text.save"); - button.clicked(() -> { - if(!invalid()){ - cons.accept(field.getText()); - hide(); - } - }); - button.setDisabled(this::invalid); - buttons().add(button); - } + private TextField field; + private Consumer listener; - public void save(){ - if(!invalid()){ - listener.accept(field.getText()); - }else{ - ui.showError("$text.editor.failoverwrite"); - } - } - - public void setFieldText(String text){ - field.setText(text); - } - - private boolean invalid(){ - if(field.getText().isEmpty()){ - return true; - } - Map map = world.maps().getByName(field.getText()); - return map != null && !map.custom; - } + public MapSaveDialog(Consumer cons){ + super("$text.editor.savemap"); + field = new TextField(); + listener = cons; + + Platform.instance.addDialog(field); + + shown(() -> { + content().clear(); + content().label(() -> { + Map map = world.maps().getByName(field.getText()); + if(map != null){ + if(map.custom){ + return "$text.editor.overwrite"; + }else{ + return "$text.editor.failoverwrite"; + } + } + return ""; + }).colspan(2); + content().row(); + content().add("$text.editor.mapname").padRight(14f); + content().add(field).size(220f, 48f); + }); + + buttons().defaults().size(200f, 50f).pad(2f); + buttons().addButton("$text.cancel", this::hide); + + TextButton button = new TextButton("$text.save"); + button.clicked(() -> { + if(!invalid()){ + cons.accept(field.getText()); + hide(); + } + }); + button.setDisabled(this::invalid); + buttons().add(button); + } + + public void save(){ + if(!invalid()){ + listener.accept(field.getText()); + }else{ + ui.showError("$text.editor.failoverwrite"); + } + } + + public void setFieldText(String text){ + field.setText(text); + } + + private boolean invalid(){ + if(field.getText().isEmpty()){ + return true; + } + Map map = world.maps().getByName(field.getText()); + return map != null && !map.custom; + } } diff --git a/core/src/io/anuke/mindustry/editor/MapView.java b/core/src/io/anuke/mindustry/editor/MapView.java index acab432e5b..e50885787a 100644 --- a/core/src/io/anuke/mindustry/editor/MapView.java +++ b/core/src/io/anuke/mindustry/editor/MapView.java @@ -33,261 +33,261 @@ import static io.anuke.mindustry.Vars.mobile; import static io.anuke.mindustry.Vars.ui; public class MapView extends Element implements GestureListener{ - private MapEditor editor; - private EditorTool tool = EditorTool.pencil; - private OperationStack stack = new OperationStack(); - private DrawOperation op; - private Bresenham2 br = new Bresenham2(); - private boolean updated = false; - private float offsetx, offsety; - private float zoom = 1f; - private boolean grid = false; - private GridImage image = new GridImage(0, 0); - private Vector2 vec = new Vector2(); - private Rectangle rect = new Rectangle(); - private Vector2[][] brushPolygons = new Vector2[MapEditor.brushSizes.length][0]; + private MapEditor editor; + private EditorTool tool = EditorTool.pencil; + private OperationStack stack = new OperationStack(); + private DrawOperation op; + private Bresenham2 br = new Bresenham2(); + private boolean updated = false; + private float offsetx, offsety; + private float zoom = 1f; + private boolean grid = false; + private GridImage image = new GridImage(0, 0); + private Vector2 vec = new Vector2(); + private Rectangle rect = new Rectangle(); + private Vector2[][] brushPolygons = new Vector2[MapEditor.brushSizes.length][0]; - private boolean drawing; - private int lastx, lasty; - private int startx, starty; - private float mousex, mousey; - private EditorTool lastTool; + private boolean drawing; + private int lastx, lasty; + private int startx, starty; + private float mousex, mousey; + private EditorTool lastTool; - public void setTool(EditorTool tool){ - this.tool = tool; - } + public MapView(MapEditor editor){ + this.editor = editor; - public EditorTool getTool() { - return tool; - } - - public void clearStack(){ - stack.clear(); - //TODO clear und obuffer - } - - public OperationStack getStack() { - return stack; - } - - public void setGrid(boolean grid) { - this.grid = grid; - } - - public boolean isGrid() { - return grid; - } - - public void undo(){ - if(stack.canUndo()){ - stack.undo(editor); - } - } - - public void redo(){ - if(stack.canRedo()){ - stack.redo(editor); - } - } - - public void addTileOp(TileOperation t){ - op.addOperation(t); - } - - public boolean checkForDuplicates(short x, short y){ - return op.checkDuplicate(x, y); - } - - public MapView(MapEditor editor){ - this.editor = editor; - - for(int i = 0; i < MapEditor.brushSizes.length; i ++){ + for(int i = 0; i < MapEditor.brushSizes.length; i++){ float size = MapEditor.brushSizes[i]; brushPolygons[i] = Geometry.pixelCircle(size, (index, x, y) -> Vector2.dst(x, y, index, index) <= index - 0.5f); } - - Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this)); - setTouchable(Touchable.enabled); - - addListener(new InputListener(){ - @Override - public boolean mouseMoved (InputEvent event, float x, float y) { - mousex = x; - mousey = y; + Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this)); + setTouchable(Touchable.enabled); - return false; + addListener(new InputListener(){ + + @Override + public boolean mouseMoved(InputEvent event, float x, float y){ + mousex = x; + mousey = y; + + return false; } - - @Override - public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - if(pointer != 0){ - return false; - } - if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){ - return true; - } + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){ + if(pointer != 0){ + return false; + } - if(button == Buttons.MIDDLE){ - lastTool = tool; - tool = EditorTool.zoom; - } + if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){ + return true; + } - mousex = x; - mousey = y; + if(button == Buttons.MIDDLE){ + lastTool = tool; + tool = EditorTool.zoom; + } - op = new DrawOperation(editor.getMap()); + mousex = x; + mousey = y; - updated = false; + op = new DrawOperation(editor.getMap()); - GridPoint2 p = project(x, y); - lastx = p.x; - lasty = p.y; - startx = p.x; - starty = p.y; - tool.touched(editor, p.x, p.y); - - if(tool.edit){ - updated = true; - ui.editor.resetSaved(); - } + updated = false; - drawing = true; - return true; - } - - @Override - public void touchUp (InputEvent event, float x, float y, int pointer, int button) { - if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){ - return; - } + GridPoint2 p = project(x, y); + lastx = p.x; + lasty = p.y; + startx = p.x; + starty = p.y; + tool.touched(editor, p.x, p.y); - drawing = false; + if(tool.edit){ + updated = true; + ui.editor.resetSaved(); + } - GridPoint2 p = project(x, y); + drawing = true; + return true; + } - if(tool == EditorTool.line){ - ui.editor.resetSaved(); - Array points = br.line(startx, starty, p.x, p.y); - for(GridPoint2 point : points){ - editor.draw(point.x, point.y); - } - updated = true; - } + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, int button){ + if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){ + return; + } - if(op != null && updated){ - if(!op.isEmpty()){ - stack.add(op); - } - op = null; - } + drawing = false; - if(lastTool != null){ - tool = lastTool; - lastTool = null; - } + GridPoint2 p = project(x, y); - } - - @Override - public void touchDragged (InputEvent event, float x, float y, int pointer) { - mousex = x; - mousey = y; + if(tool == EditorTool.line){ + ui.editor.resetSaved(); + Array points = br.line(startx, starty, p.x, p.y); + for(GridPoint2 point : points){ + editor.draw(point.x, point.y); + } + updated = true; + } - GridPoint2 p = project(x, y); - - if(drawing && tool.draggable){ - ui.editor.resetSaved(); - Array points = br.line(lastx, lasty, p.x, p.y); - for(GridPoint2 point : points){ - tool.touched(editor, point.x, point.y); - } - updated = true; - } - lastx = p.x; - lasty = p.y; - } - }); - } - - @Override - public void act(float delta){ - super.act(delta); + if(op != null && updated){ + if(!op.isEmpty()){ + stack.add(op); + } + op = null; + } - if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) && - !Inputs.keyDown(io.anuke.ucore.input.Input.CONTROL_LEFT)) { - float ax = Inputs.getAxis("move_x"); - float ay = Inputs.getAxis("move_y"); - offsetx -= ax * 15f / zoom; - offsety -= ay * 15f / zoom; - } + if(lastTool != null){ + tool = lastTool; + lastTool = null; + } - if(ui.editor.hasPane()) return; - - zoom += Inputs.scroll()/10f * zoom; - clampZoom(); - } - - private void clampZoom(){ - zoom = Mathf.clamp(zoom, 0.2f, 12f); - } - - private GridPoint2 project(float x, float y){ - float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height()); - float size = Math.min(width, height); - float sclwidth = size * zoom; - float sclheight = size * zoom * ratio; - x = (x - getWidth()/2 + sclwidth/2 - offsetx*zoom) / sclwidth * editor.getMap().width(); - y = (y - getHeight()/2 + sclheight/2 - offsety*zoom) / sclheight * editor.getMap().height(); + } - if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){ - return Tmp.g1.set((int)(x - 0.5f), (int)(y - 0.5f)); - }else{ - return Tmp.g1.set((int)x, (int)y); - } - } + @Override + public void touchDragged(InputEvent event, float x, float y, int pointer){ + mousex = x; + mousey = y; - private Vector2 unproject(int x, int y){ - float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height()); - float size = Math.min(width, height); - float sclwidth = size * zoom; - float sclheight = size * zoom * ratio; - float px = ((float)x / editor.getMap().width()) * sclwidth + offsetx*zoom - sclwidth/2 + getWidth()/2; - float py = ((float)(y) / editor.getMap().height()) * sclheight - + offsety*zoom - sclheight/2 + getHeight()/2; - return vec.set(px, py); - } + GridPoint2 p = project(x, y); - @Override - public void draw(Batch batch, float alpha){ - float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height()); - float size = Math.min(width, height); - float sclwidth = size * zoom; - float sclheight = size * zoom * ratio; - float centerx = x + width/2 + offsetx * zoom; - float centery = y + height/2 + offsety * zoom; + if(drawing && tool.draggable){ + ui.editor.resetSaved(); + Array points = br.line(lastx, lasty, p.x, p.y); + for(GridPoint2 point : points){ + tool.touched(editor, point.x, point.y); + } + updated = true; + } + lastx = p.x; + lasty = p.y; + } + }); + } - image.setImageSize(editor.getMap().width(), editor.getMap().height()); - - batch.flush(); - boolean pop = ScissorStack.pushScissors(rect.set(x, y, width, height)); + public EditorTool getTool(){ + return tool; + } - Draw.color(Color.LIGHT_GRAY); - Lines.stroke(-2f); - Lines.rect(centerx - sclwidth/2 - 1, centery - sclheight/2 - 1, sclwidth + 2, sclheight + 2); - editor.renderer().draw(centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight); - Draw.reset(); + public void setTool(EditorTool tool){ + this.tool = tool; + } - if(grid){ - Draw.color(Color.GRAY); - image.setBounds(centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight); - image.draw(batch, alpha); - Draw.color(); - } + public void clearStack(){ + stack.clear(); + //TODO clear und obuffer + } + + public OperationStack getStack(){ + return stack; + } + + public boolean isGrid(){ + return grid; + } + + public void setGrid(boolean grid){ + this.grid = grid; + } + + public void undo(){ + if(stack.canUndo()){ + stack.undo(editor); + } + } + + public void redo(){ + if(stack.canRedo()){ + stack.redo(editor); + } + } + + public void addTileOp(TileOperation t){ + op.addOperation(t); + } + + public boolean checkForDuplicates(short x, short y){ + return op.checkDuplicate(x, y); + } + + @Override + public void act(float delta){ + super.act(delta); + + if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) && + !Inputs.keyDown(io.anuke.ucore.input.Input.CONTROL_LEFT)){ + float ax = Inputs.getAxis("move_x"); + float ay = Inputs.getAxis("move_y"); + offsetx -= ax * 15f / zoom; + offsety -= ay * 15f / zoom; + } + + if(ui.editor.hasPane()) return; + + zoom += Inputs.scroll() / 10f * zoom; + clampZoom(); + } + + private void clampZoom(){ + zoom = Mathf.clamp(zoom, 0.2f, 12f); + } + + private GridPoint2 project(float x, float y){ + float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height()); + float size = Math.min(width, height); + float sclwidth = size * zoom; + float sclheight = size * zoom * ratio; + x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.getMap().width(); + y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.getMap().height(); + + if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){ + return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f)); + }else{ + return Tmp.g1.set((int) x, (int) y); + } + } + + private Vector2 unproject(int x, int y){ + float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height()); + float size = Math.min(width, height); + float sclwidth = size * zoom; + float sclheight = size * zoom * ratio; + float px = ((float) x / editor.getMap().width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2; + float py = ((float) (y) / editor.getMap().height()) * sclheight + + offsety * zoom - sclheight / 2 + getHeight() / 2; + return vec.set(px, py); + } + + @Override + public void draw(Batch batch, float alpha){ + float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height()); + float size = Math.min(width, height); + float sclwidth = size * zoom; + float sclheight = size * zoom * ratio; + float centerx = x + width / 2 + offsetx * zoom; + float centery = y + height / 2 + offsety * zoom; + + image.setImageSize(editor.getMap().width(), editor.getMap().height()); + + batch.flush(); + boolean pop = ScissorStack.pushScissors(rect.set(x, y, width, height)); + + Draw.color(Color.LIGHT_GRAY); + Lines.stroke(-2f); + Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2); + editor.renderer().draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight); + Draw.reset(); + + if(grid){ + Draw.color(Color.GRAY); + image.setBounds(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight); + image.draw(batch, alpha); + Draw.color(); + } int index = 0; - for(int i = 0; i < MapEditor.brushSizes.length; i ++){ + for(int i = 0; i < MapEditor.brushSizes.length; i++){ if(editor.getBrushSize() == MapEditor.brushSizes[i]){ index = i; break; @@ -297,102 +297,102 @@ public class MapView extends Element implements GestureListener{ //todo is it really math.max? float scaling = zoom * Math.min(width, height) / Math.max(editor.getMap().width(), editor.getMap().height()); - Draw.color(Palette.accent); - Lines.stroke(Unit.dp.scl(1f * zoom)); + Draw.color(Palette.accent); + Lines.stroke(Unit.dp.scl(1f * zoom)); - if(!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser) { - if (tool == EditorTool.line && drawing) { - Vector2 v1 = unproject(startx, starty).add(x, y); - float sx = v1.x, sy = v1.y; - Vector2 v2 = unproject(lastx, lasty).add(x, y); + if(!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser){ + if(tool == EditorTool.line && drawing){ + Vector2 v1 = unproject(startx, starty).add(x, y); + float sx = v1.x, sy = v1.y; + Vector2 v2 = unproject(lastx, lasty).add(x, y); - Lines.poly(brushPolygons[index], sx, sy, scaling); - Lines.poly(brushPolygons[index], v2.x, v2.y, scaling); - } + Lines.poly(brushPolygons[index], sx, sy, scaling); + Lines.poly(brushPolygons[index], v2.x, v2.y, scaling); + } - if (tool.edit && (!mobile || drawing)) { - GridPoint2 p = project(mousex, mousey); - Vector2 v = unproject(p.x, p.y).add(x, y); - Lines.poly(brushPolygons[index], v.x, v.y, scaling); - } - }else{ - if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){ - GridPoint2 p = project(mousex, mousey); - Vector2 v = unproject(p.x, p.y).add(x, y); - float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling/2f : 0f); - Lines.square( - v.x + scaling/2f + offset, - v.y + scaling/2f + offset, - scaling * editor.getDrawBlock().size /2f); - } - } + if(tool.edit && (!mobile || drawing)){ + GridPoint2 p = project(mousex, mousey); + Vector2 v = unproject(p.x, p.y).add(x, y); + Lines.poly(brushPolygons[index], v.x, v.y, scaling); + } + }else{ + if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){ + GridPoint2 p = project(mousex, mousey); + Vector2 v = unproject(p.x, p.y).add(x, y); + float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling / 2f : 0f); + Lines.square( + v.x + scaling / 2f + offset, + v.y + scaling / 2f + offset, + scaling * editor.getDrawBlock().size / 2f); + } + } - batch.flush(); - - if(pop) ScissorStack.popScissors(); - - Draw.color(Palette.accent); - Lines.stroke(Unit.dp.scl(3f)); - Lines.rect(x, y, width, height); - Draw.reset(); - } - - private boolean active(){ - return Core.scene.getKeyboardFocus() != null - && Core.scene.getKeyboardFocus().isDescendantOf(ui.editor) - && ui.editor.isShown() && tool == EditorTool.zoom && - Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this; - } + batch.flush(); - @Override - public boolean touchDown(float x, float y, int pointer, int button){ - return false; - } + if(pop) ScissorStack.popScissors(); - @Override - public boolean tap(float x, float y, int count, int button){ - return false; - } + Draw.color(Palette.accent); + Lines.stroke(Unit.dp.scl(3f)); + Lines.rect(x, y, width, height); + Draw.reset(); + } - @Override - public boolean longPress(float x, float y){ - return false; - } + private boolean active(){ + return Core.scene.getKeyboardFocus() != null + && Core.scene.getKeyboardFocus().isDescendantOf(ui.editor) + && ui.editor.isShown() && tool == EditorTool.zoom && + Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this; + } - @Override - public boolean fling(float velocityX, float velocityY, int button){ - return false; - } + @Override + public boolean touchDown(float x, float y, int pointer, int button){ + return false; + } - @Override - public boolean pan(float x, float y, float deltaX, float deltaY){ - if(!active()) return false; - offsetx += deltaX / zoom; - offsety -= deltaY / zoom; - return false; - } + @Override + public boolean tap(float x, float y, int count, int button){ + return false; + } - @Override - public boolean panStop(float x, float y, int pointer, int button){ - return false; - } + @Override + public boolean longPress(float x, float y){ + return false; + } - @Override - public boolean zoom(float initialDistance, float distance){ - if(!active()) return false; - float nzoom = distance - initialDistance; - zoom += nzoom / 10000f / Unit.dp.scl(1f) * zoom; - clampZoom(); - return false; - } + @Override + public boolean fling(float velocityX, float velocityY, int button){ + return false; + } - @Override - public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){ - return false; - } + @Override + public boolean pan(float x, float y, float deltaX, float deltaY){ + if(!active()) return false; + offsetx += deltaX / zoom; + offsety -= deltaY / zoom; + return false; + } - @Override - public void pinchStop(){ + @Override + public boolean panStop(float x, float y, int pointer, int button){ + return false; + } - } + @Override + public boolean zoom(float initialDistance, float distance){ + if(!active()) return false; + float nzoom = distance - initialDistance; + zoom += nzoom / 10000f / Unit.dp.scl(1f) * zoom; + clampZoom(); + return false; + } + + @Override + public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){ + return false; + } + + @Override + public void pinchStop(){ + + } } diff --git a/core/src/io/anuke/mindustry/editor/OperationStack.java b/core/src/io/anuke/mindustry/editor/OperationStack.java index 5c739608ee..402da3cf5e 100755 --- a/core/src/io/anuke/mindustry/editor/OperationStack.java +++ b/core/src/io/anuke/mindustry/editor/OperationStack.java @@ -3,49 +3,49 @@ package io.anuke.mindustry.editor; import com.badlogic.gdx.utils.Array; public class OperationStack{ - private final static int maxSize = 10; - private Array stack = new Array<>(); - private int index = 0; - - public OperationStack(){ - - } - - public void clear(){ - stack.clear(); - index = 0; - } - - public void add(DrawOperation action){ - stack.truncate(stack.size + index); - index = 0; - stack.add(action); + private final static int maxSize = 10; + private Array stack = new Array<>(); + private int index = 0; - if(stack.size > maxSize){ + public OperationStack(){ + + } + + public void clear(){ + stack.clear(); + index = 0; + } + + public void add(DrawOperation action){ + stack.truncate(stack.size + index); + index = 0; + stack.add(action); + + if(stack.size > maxSize){ stack.removeIndex(0); } - } - - public boolean canUndo(){ - return !(stack.size - 1 + index < 0); - } - - public boolean canRedo(){ - return !(index > -1 || stack.size + index < 0); - } + } - public void undo(MapEditor editor){ - if(!canUndo()) return; + public boolean canUndo(){ + return !(stack.size - 1 + index < 0); + } - stack.get(stack.size - 1 + index).undo(editor); - index --; - } + public boolean canRedo(){ + return !(index > -1 || stack.size + index < 0); + } - public void redo(MapEditor editor){ - if(!canRedo()) return; - - index ++; - stack.get(stack.size - 1 + index).redo(editor); - - } + public void undo(MapEditor editor){ + if(!canUndo()) return; + + stack.get(stack.size - 1 + index).undo(editor); + index--; + } + + public void redo(MapEditor editor){ + if(!canRedo()) return; + + index++; + stack.get(stack.size - 1 + index).redo(editor); + + } } diff --git a/core/src/io/anuke/mindustry/entities/Damage.java b/core/src/io/anuke/mindustry/entities/Damage.java index 6ba29a3de3..0c7ac56454 100644 --- a/core/src/io/anuke/mindustry/entities/Damage.java +++ b/core/src/io/anuke/mindustry/entities/Damage.java @@ -24,84 +24,90 @@ import io.anuke.ucore.util.Translator; import static io.anuke.mindustry.Vars.*; -/**Utility class for damaging in an area.*/ -public class Damage { - private static Rectangle rect = new Rectangle(); - private static Rectangle hitrect = new Rectangle(); - private static Translator tr = new Translator(); +/** + * Utility class for damaging in an area. + */ +public class Damage{ + private static Rectangle rect = new Rectangle(); + private static Rectangle hitrect = new Rectangle(); + private static Translator tr = new Translator(); - /**Creates a dynamic explosion based on specified parameters.*/ - public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){ - for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i ++){ - int branches = 5 + Mathf.clamp((int)(power/30), 1, 20); - Timers.run(i*2f + Mathf.random(4f), () -> Lightning.create(Team.none, Fx.none, Palette.power, 3, - x, y, Mathf.random(360f), branches + Mathf.range(2))); - } + /** + * Creates a dynamic explosion based on specified parameters. + */ + public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){ + for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){ + int branches = 5 + Mathf.clamp((int) (power / 30), 1, 20); + Timers.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.none, Fx.none, Palette.power, 3, + x, y, Mathf.random(360f), branches + Mathf.range(2))); + } - for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i ++){ - Timers.run(i/2, () -> CallEntity.createBullet(TurretBullets.fireball, x, y, Mathf.random(360f))); - } + for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){ + Timers.run(i / 2, () -> CallEntity.createBullet(TurretBullets.fireball, x, y, Mathf.random(360f))); + } - int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30); + int waves = Mathf.clamp((int) (explosiveness / 4), 0, 30); - for(int i = 0; i < waves; i ++){ - int f = i; - Timers.run(i*2f, () -> { - Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f)/waves), explosiveness/2f); - Effects.effect(ExplosionFx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius)); - }); - } + for(int i = 0; i < waves; i++){ + int f = i; + Timers.run(i * 2f, () -> { + Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f); + Effects.effect(ExplosionFx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius)); + }); + } - if(explosiveness > 15f){ - Effects.effect(ExplosionFx.shockwave, x, y); - } + if(explosiveness > 15f){ + Effects.effect(ExplosionFx.shockwave, x, y); + } - if(explosiveness > 30f){ - Effects.effect(ExplosionFx.bigShockwave, x, y); - } + if(explosiveness > 30f){ + Effects.effect(ExplosionFx.bigShockwave, x, y); + } - float shake = Math.min(explosiveness/4f + 3f, 9f); - Effects.shake(shake, shake, x, y); - Effects.effect(ExplosionFx.blockExplosion, x, y); - } + float shake = Math.min(explosiveness / 4f + 3f, 9f); + Effects.shake(shake, shake, x, y); + Effects.effect(ExplosionFx.blockExplosion, x, y); + } - public static void createIncend(float x, float y, float range, int amount){ - for (int i = 0; i < amount; i++) { - float cx = x + Mathf.range(range); - float cy = y + Mathf.range(range); - Tile tile = world.tileWorld(cx, cy); - if(tile != null){ - Fire.create(tile); - } - } - } + public static void createIncend(float x, float y, float range, int amount){ + for(int i = 0; i < amount; i++){ + float cx = x + Mathf.range(range); + float cy = y + Mathf.range(range); + Tile tile = world.tileWorld(cx, cy); + if(tile != null){ + Fire.create(tile); + } + } + } - /**Damages entities in a line. - * Only enemies of the specified team are damaged.*/ - public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){ - tr.trns(angle, length); - rect.setPosition(x, y).setSize(tr.x, tr.y); - float x2 = tr.x + x, y2 = tr.y + y; + /** + * Damages entities in a line. + * Only enemies of the specified team are damaged. + */ + public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){ + tr.trns(angle, length); + rect.setPosition(x, y).setSize(tr.x, tr.y); + float x2 = tr.x + x, y2 = tr.y + y; - if(rect.width < 0){ - rect.x += rect.width; - rect.width *= -1; - } + if(rect.width < 0){ + rect.x += rect.width; + rect.width *= -1; + } - if(rect.height < 0){ - rect.y += rect.height; - rect.height *= -1; - } + if(rect.height < 0){ + rect.y += rect.height; + rect.height *= -1; + } - float expand = 3f; + float expand = 3f; - rect.y -= expand; - rect.x -= expand; - rect.width += expand*2; - rect.height += expand*2; + rect.y -= expand; + rect.x -= expand; + rect.width += expand * 2; + rect.height += expand * 2; Consumer cons = e -> { - e.getHitbox(hitrect); + e.getHitbox(hitrect); Rectangle other = hitrect; other.y -= expand; other.x -= expand; @@ -110,79 +116,85 @@ public class Damage { Vector2 vec = Physics.raycastRect(x, y, x2, y2, other); - if (vec != null) { + if(vec != null){ Effects.effect(effect, vec.x, vec.y); e.collision(hitter, vec.x, vec.y); hitter.collision(e, vec.x, vec.y); } }; - Units.getNearbyEnemies(team, rect, cons); - } + Units.getNearbyEnemies(team, rect, cons); + } - /**Damages all entities and blocks in a radius that are enemies of the team.*/ - public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate predicate, Consumer acceptor) { - Consumer cons = entity -> { - if(!predicate.test(entity)) return; + /** + * Damages all entities and blocks in a radius that are enemies of the team. + */ + public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate predicate, Consumer acceptor){ + Consumer cons = entity -> { + if(!predicate.test(entity)) return; - entity.getHitbox(hitrect); - if (!hitrect.overlaps(rect)) { - return; - } - entity.damage(damage); - acceptor.accept(entity); - }; + entity.getHitbox(hitrect); + if(!hitrect.overlaps(rect)){ + return; + } + entity.damage(damage); + acceptor.accept(entity); + }; - rect.setSize(size * 2).setCenter(x, y); - if (team != null) { - Units.getNearbyEnemies(team, rect, cons); - } else { - Units.getNearby(rect, cons); - } - } + rect.setSize(size * 2).setCenter(x, y); + if(team != null){ + Units.getNearbyEnemies(team, rect, cons); + }else{ + Units.getNearby(rect, cons); + } + } - /**Damages everything in a radius.*/ - public static void damage(float x, float y, float radius, float damage){ - damage(null, x, y, radius, damage); - } + /** + * Damages everything in a radius. + */ + public static void damage(float x, float y, float radius, float damage){ + damage(null, x, y, radius, damage); + } - /**Damages all entities and blocks in a radius that are enemies of the team.*/ - public static void damage(Team team, float x, float y, float radius, float damage){ - Consumer cons = entity -> { - if(entity.team == team || entity.distanceTo(x, y) > radius){ - return; - } - float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage); - entity.damage(amount); - //TODO better velocity displacement - float dst = tr.set(entity.x - x, entity.y - y).len(); - entity.getVelocity().add(tr.setLength((1f-dst/radius) * 2f)); - }; + /** + * Damages all entities and blocks in a radius that are enemies of the team. + */ + public static void damage(Team team, float x, float y, float radius, float damage){ + Consumer cons = entity -> { + if(entity.team == team || entity.distanceTo(x, y) > radius){ + return; + } + float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage); + entity.damage(amount); + //TODO better velocity displacement + float dst = tr.set(entity.x - x, entity.y - y).len(); + entity.getVelocity().add(tr.setLength((1f - dst / radius) * 2f)); + }; - rect.setSize(radius *2).setCenter(x, y); - if(team != null) { - Units.getNearbyEnemies(team, rect, cons); - }else{ - Units.getNearby(rect, cons); - } + rect.setSize(radius * 2).setCenter(x, y); + if(team != null){ + Units.getNearbyEnemies(team, rect, cons); + }else{ + Units.getNearby(rect, cons); + } - int trad = (int)(radius / tilesize); - for(int dx = -trad; dx <= trad; dx ++){ - for(int dy= -trad; dy <= trad; dy ++){ - Tile tile = world.tile(Mathf.scl2(x, tilesize) + dx, Mathf.scl2(y, tilesize) + dy); - if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Vector2.dst(dx, dy, 0, 0) <= trad){ - float amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage); - tile.entity.damage(amount); - } - } - } + int trad = (int) (radius / tilesize); + for(int dx = -trad; dx <= trad; dx++){ + for(int dy = -trad; dy <= trad; dy++){ + Tile tile = world.tile(Mathf.scl2(x, tilesize) + dx, Mathf.scl2(y, tilesize) + dy); + if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Vector2.dst(dx, dy, 0, 0) <= trad){ + float amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage); + tile.entity.damage(amount); + } + } + } - } - - private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){ - float dist = Vector2.dst(x, y, tx, ty); - float falloff = 0.4f; - float scaled = Mathf.lerp(1f - dist/radius, 1f, falloff); - return damage * scaled; - } + } + + private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){ + float dist = Vector2.dst(x, y, tx, ty); + float falloff = 0.4f; + float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff); + return damage * scaled; + } } diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index 42c14c2a38..9a4641dce2 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -9,6 +9,7 @@ import com.badlogic.gdx.utils.Queue; import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.Remote; import io.anuke.mindustry.Vars; +import io.anuke.mindustry.content.Mechs; import io.anuke.mindustry.entities.effect.ItemDrop; import io.anuke.mindustry.entities.effect.ScorchDecal; import io.anuke.mindustry.entities.traits.*; @@ -25,7 +26,10 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Floor; import io.anuke.mindustry.world.blocks.storage.CoreBlock.CoreEntity; import io.anuke.mindustry.world.blocks.units.MechFactory; -import io.anuke.ucore.core.*; +import io.anuke.ucore.core.Core; +import io.anuke.ucore.core.Graphics; +import io.anuke.ucore.core.Inputs; +import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.entities.trait.SolidTrait; import io.anuke.ucore.graphics.Draw; @@ -38,87 +42,109 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait { - private static final int timerShootLeft = 0; - private static final int timerShootRight = 1; +public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait{ + public static final int timerSync = 2; + private static final int timerShootLeft = 0; + private static final int timerShootRight = 1; - public static final int timerSync = 2; + //region instance variables, constructor + public float baseRotation; - //region instance variables, constructor + public float pointerX, pointerY; + public String name = "name"; + public String uuid, usid; + public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile; + public float boostHeat; + public Color color = new Color(); + public Mech mech; + public int spawner; - public float baseRotation; + public NetConnection con; + public int playerIndex = 0; + public boolean isLocal = false; + public Timer timer = new Timer(4); + public TargetTrait target; + public TargetTrait moveTarget; - public float pointerX, pointerY; - public String name = "name"; - public String uuid, usid; - public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile; - public float boostHeat; - public Color color = new Color(); - public Mech mech; - public int spawner; + private float walktime; + private Queue placeQueue = new ThreadQueue<>(); + private Tile mining; + private CarriableTrait carrying; + private Trail trail = new Trail(12); + private Vector2 movement = new Vector2(); + private boolean moved; - public NetConnection con; - public int playerIndex = 0; - public boolean isLocal = false; - public Timer timer = new Timer(4); - public TargetTrait target; - public TargetTrait moveTarget; + public Player(){ + hitbox.setSize(5); + hitboxTile.setSize(4f); + } - private float walktime; - private Queue placeQueue = new ThreadQueue<>(); - private Tile mining; - private CarriableTrait carrying; - private Trail trail = new Trail(12); - private Vector2 movement = new Vector2(); - private boolean moved; - - public Player(){ - hitbox.setSize(5); - hitboxTile.setSize(4f); - } + //endregion - //endregion + //region unit and event overrides, utility methods - //region unit and event overrides, utility methods + @Remote(in = In.entities, targets = Loc.server, called = Loc.server) + public static void onPlayerDamage(Player player, float amount){ + if(player == null) return; + player.hitTime = hitDuration; + player.health -= amount; + } - @Override - public Timer getTimer() { - return timer; - } + @Remote(in = In.entities, targets = Loc.server, called = Loc.server) + public static void onPlayerDeath(Player player){ + if(player == null) return; - @Override - public int getShootTimer(boolean left) { - return left ? timerShootLeft : timerShootRight; - } + player.dead = true; + player.placeQueue.clear(); - @Override - public Weapon getWeapon() { - return mech.weapon; - } + player.dropCarry(); - @Override - public float getMinePower() { - return mech.mineSpeed; - } + float explosiveness = 2f + (player.inventory.hasItem() ? player.inventory.getItem().item.explosiveness * player.inventory.getItem().amount : 0f); + float flammability = (player.inventory.hasItem() ? player.inventory.getItem().item.flammability * player.inventory.getItem().amount : 0f); + Damage.dynamicExplosion(player.x, player.y, flammability, explosiveness, 0f, player.getSize() / 2f, Palette.darkFlame); - @Override - public TextureRegion getIconRegion() { - return mech.iconRegion; - } + ScorchDecal.create(player.x, player.y); + player.onDeath(); + } - @Override - public int getItemCapacity() { - return mech.itemCapacity; - } + @Override + public Timer getTimer(){ + return timer; + } - @Override - public int getAmmoCapacity() { - return mech.ammoCapacity; - } + @Override + public int getShootTimer(boolean left){ + return left ? timerShootLeft : timerShootRight; + } - @Override - public void interpolate() { + @Override + public Weapon getWeapon(){ + return mech.weapon; + } + + @Override + public float getMinePower(){ + return mech.mineSpeed; + } + + @Override + public TextureRegion getIconRegion(){ + return mech.iconRegion; + } + + @Override + public int getItemCapacity(){ + return mech.itemCapacity; + } + + @Override + public int getAmmoCapacity(){ + return mech.ammoCapacity; + } + + @Override + public void interpolate(){ super.interpolate(); if(interpolator.values.length > 1){ @@ -130,568 +156,560 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra } } - @Override - public CarriableTrait getCarry() { - return carrying; - } - - @Override - public void setCarry(CarriableTrait unit) { - this.carrying = unit; - } - - @Override - public float getCarryWeight() { - return mech.carryWeight; - } - - @Override - public float getBuildPower(Tile tile) { - return mech.buildPower; - } - - @Override - public float maxHealth() { - return 200; - } - - @Override - public Tile getMineTile() { - return mining; - } - - @Override - public void setMineTile(Tile tile) { - this.mining = tile; - } - - @Override - public float getArmor() { - return mech.armor; - } - - @Override - public boolean acceptsAmmo(Item item) { - return mech.weapon.getAmmoType(item) != null && inventory.canAcceptAmmo(mech.weapon.getAmmoType(item)); - } - - @Override - public void added() { - baseRotation = 90f; - } - - @Override - public void addAmmo(Item item) { - inventory.addAmmo(mech.weapon.getAmmoType(item)); - } - - @Override - public float getMass(){ - return mech.mass; + @Override + public CarriableTrait getCarry(){ + return carrying; } @Override - public boolean isFlying(){ - return mech.flying || noclip || isCarried(); - } + public void setCarry(CarriableTrait unit){ + this.carrying = unit; + } - @Override - public float getSize() { - return 8; - } + @Override + public float getCarryWeight(){ + return mech.carryWeight; + } - @Override - public void damage(float amount){ - CallEntity.onPlayerDamage(this, calculateDamage(amount)); + @Override + public float getBuildPower(Tile tile){ + return mech.buildPower; + } - if(health <= 0 && !dead){ - CallEntity.onPlayerDeath(this); - } - } + @Override + public float maxHealth(){ + return 200; + } - @Override - public boolean collides(SolidTrait other) { - return super.collides(other) || other instanceof ItemDrop; - } + @Override + public Tile getMineTile(){ + return mining; + } - @Remote(in = In.entities, targets = Loc.server, called = Loc.server) - public static void onPlayerDamage(Player player, float amount){ - if(player == null) return; + @Override + public void setMineTile(Tile tile){ + this.mining = tile; + } - player.hitTime = hitDuration; - player.health -= amount; - } + @Override + public float getArmor(){ + return mech.armor; + } - @Remote(in = In.entities, targets = Loc.server, called = Loc.server) - public static void onPlayerDeath(Player player){ - if(player == null) return; + @Override + public boolean acceptsAmmo(Item item){ + return mech.weapon.getAmmoType(item) != null && inventory.canAcceptAmmo(mech.weapon.getAmmoType(item)); + } - player.dead = true; - player.placeQueue.clear(); + @Override + public void added(){ + baseRotation = 90f; + } - player.dropCarry(); + @Override + public void addAmmo(Item item){ + inventory.addAmmo(mech.weapon.getAmmoType(item)); + } - float explosiveness = 2f + (player.inventory.hasItem() ? player.inventory.getItem().item.explosiveness * player.inventory.getItem().amount : 0f); - float flammability = (player.inventory.hasItem() ? player.inventory.getItem().item.flammability * player.inventory.getItem().amount : 0f); - Damage.dynamicExplosion(player.x, player.y, flammability, explosiveness, 0f, player.getSize()/2f, Palette.darkFlame); + @Override + public float getMass(){ + return mech.mass; + } - ScorchDecal.create(player.x, player.y); - player.onDeath(); - } + @Override + public boolean isFlying(){ + return mech.flying || noclip || isCarried(); + } - @Override - public void set(float x, float y){ - this.x = x; - this.y = y; + @Override + public float getSize(){ + return 8; + } - if(isFlying() && isLocal){ - Core.camera.position.set(x, y, 0f); - } - } + @Override + public void damage(float amount){ + CallEntity.onPlayerDamage(this, calculateDamage(amount)); - @Override - public void removed() { + if(health <= 0 && !dead){ + CallEntity.onPlayerDeath(this); + } + } + + @Override + public boolean collides(SolidTrait other){ + return super.collides(other) || other instanceof ItemDrop; + } + + @Override + public void set(float x, float y){ + this.x = x; + this.y = y; + + if(isFlying() && isLocal){ + Core.camera.position.set(x, y, 0f); + } + } + + @Override + public void removed(){ dropCarryLocal(); TileEntity core = getClosestCore(); - if(core != null && ((CoreEntity)core).currentUnit == this){ - ((CoreEntity)core).currentUnit = null; - } - } + if(core != null && ((CoreEntity) core).currentUnit == this){ + ((CoreEntity) core).currentUnit = null; + } + } - @Override - public EntityGroup targetGroup() { - return playerGroup; - } + @Override + public EntityGroup targetGroup(){ + return playerGroup; + } - //endregion + //endregion - //region draw methods + //region draw methods - @Override - public float drawSize() { - return isLocal ? Float.MAX_VALUE : 40; - } + @Override + public float drawSize(){ + return isLocal ? Float.MAX_VALUE : 40; + } - @Override - public void draw(){ - if((debug && (!showPlayer || !showUI)) || dead) return; + @Override + public void drawShadow(){ + Draw.rect(mech.iconRegion, x + elevation * elevationScale, y - elevation * elevationScale, rotation - 90); + } - if(!movement.isZero() && moved){ - walktime += Timers.delta() * movement.len()/0.7f * getFloorOn().speedMultiplier; - baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f); - } + @Override + public void draw(){ + if((debug && (!showPlayer || !showUI)) || dead) return; - boostHeat = Mathf.lerpDelta(boostHeat, isBoosting && ((!movement.isZero() && moved) || !isLocal) ? 1f : 0f, 0.08f); + if(!movement.isZero() && moved){ + walktime += Timers.delta() * movement.len() / 0.7f * getFloorOn().speedMultiplier; + baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f); + } + + boostHeat = Mathf.lerpDelta(boostHeat, isBoosting && ((!movement.isZero() && moved) || !isLocal) ? 1f : 0f, 0.08f); boolean snap = snapCamera && isLocal; - float px = x, py =y; + float px = x, py = y; - if(snap){ - x = (int)(x + 0.0001f); - y = (int)(y + 0.0001f); - } - - float ft = Mathf.sin(walktime, 6f, 2f) * (1f-boostHeat); - - Floor floor = getFloorOn(); - - Draw.color(); - Draw.alpha(hitTime / hitDuration); - - if(!mech.flying) { - if(floor.isLiquid){ - Draw.tint(Color.WHITE, floor.liquidColor, 0.5f); - } - - float boostTrnsY = -boostHeat * 3f; - float boostTrnsX = boostHeat * 3f; - float boostAng = boostHeat*40f; - - for (int i : Mathf.signs) { - Draw.rect(mech.legRegion, - x + Angles.trnsx(baseRotation, ft * i + boostTrnsY, -boostTrnsX*i), - y + Angles.trnsy(baseRotation, ft * i + boostTrnsY, -boostTrnsX*i), - 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90 + boostAng*i); - } - - Draw.rect(mech.baseRegion, x, y, baseRotation- 90); - } - - if(floor.isLiquid) { - Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f); - }else { - Draw.tint(Color.WHITE); - } - - Draw.rect(mech.region, x, y, rotation -90); - - for (int i : Mathf.signs) { - float tra = rotation - 90, trY = - mech.weapon.getRecoil(this, i > 0) + mech.weaponOffsetY; - float w = i > 0 ? -12 : 12; - Draw.rect(mech.weapon.equipRegion, - x + Angles.trnsx(tra, mech.weaponOffsetX * i, trY), - y + Angles.trnsy(tra, mech.weaponOffsetX * i, trY), w, 12, rotation - 90); - } - - float backTrns = 4f, itemSize = 5f; - if(inventory.hasItem()){ - ItemStack stack = inventory.getItem(); - int stored = Mathf.clamp(stack.amount / 6, 1, 8); - - for(int i = 0; i < stored; i ++) { - float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 1, 60f); - float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 1f) - 1f; - Draw.rect(stack.item.region, - x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT), - y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT), - itemSize, itemSize, rotation); - } - } - - Draw.alpha(1f); - - x = px; - y = py; - } - - @Override - public void drawOver(){ - if(dead) return; - - if(!isShooting()) { - drawBuilding(this); + if(snap){ + x = (int) (x + 0.0001f); + y = (int) (y + 0.0001f); } - if(mech.flying || boostHeat > 0.001f){ - float wobblyness = 0.6f; - trail.update(x + Angles.trnsx(rotation + 180f, 5f) + Mathf.range(wobblyness), - y + Angles.trnsy(rotation + 180f, 5f) + Mathf.range(wobblyness)); - trail.draw(mech.trailColor, mech.trailColor, 5f * (isFlying() ? 1f : boostHeat)); - }else{ - trail.clear(); - } + float ft = Mathf.sin(walktime, 6f, 2f) * (1f - boostHeat); + + Floor floor = getFloorOn(); + + Draw.color(); + Draw.alpha(hitTime / hitDuration); + + if(!mech.flying){ + if(floor.isLiquid){ + Draw.tint(Color.WHITE, floor.liquidColor, 0.5f); + } + + float boostTrnsY = -boostHeat * 3f; + float boostTrnsX = boostHeat * 3f; + float boostAng = boostHeat * 40f; + + for(int i : Mathf.signs){ + Draw.rect(mech.legRegion, + x + Angles.trnsx(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), + y + Angles.trnsy(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), + 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90 + boostAng * i); + } + + Draw.rect(mech.baseRegion, x, y, baseRotation - 90); + } + + if(floor.isLiquid){ + Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f); + }else{ + Draw.tint(Color.WHITE); + } + + Draw.rect(mech.region, x, y, rotation - 90); + + for(int i : Mathf.signs){ + float tra = rotation - 90, trY = -mech.weapon.getRecoil(this, i > 0) + mech.weaponOffsetY; + float w = i > 0 ? -12 : 12; + Draw.rect(mech.weapon.equipRegion, + x + Angles.trnsx(tra, mech.weaponOffsetX * i, trY), + y + Angles.trnsy(tra, mech.weaponOffsetX * i, trY), w, 12, rotation - 90); + } + + float backTrns = 4f, itemSize = 5f; + if(inventory.hasItem()){ + ItemStack stack = inventory.getItem(); + int stored = Mathf.clamp(stack.amount / 6, 1, 8); + + for(int i = 0; i < stored; i++){ + float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 1, 60f); + float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 1f) - 1f; + Draw.rect(stack.item.region, + x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT), + y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT), + itemSize, itemSize, rotation); + } + } + + Draw.alpha(1f); + + x = px; + y = py; + } + + @Override + public void drawOver(){ + if(dead) return; + + if(!isShooting()){ + drawBuilding(this); + } + + if(mech.flying || boostHeat > 0.001f){ + float wobblyness = 0.6f; + trail.update(x + Angles.trnsx(rotation + 180f, 5f) + Mathf.range(wobblyness), + y + Angles.trnsy(rotation + 180f, 5f) + Mathf.range(wobblyness)); + trail.draw(mech.trailColor, 5f * (isFlying() ? 1f : boostHeat)); + }else{ + trail.clear(); + } } public void drawName(){ - GlyphLayout layout = Pools.obtain(GlyphLayout.class); - - Draw.tscl(0.25f/2); - layout.setText(Core.font, name); - Draw.color(0f, 0f, 0f, 0.3f); - Draw.rect("blank", x, y + 8 - layout.height/2, layout.width + 2, layout.height + 2); - Draw.color(); - Draw.tcolor(color); - Draw.text(name, x, y + 8); - - if(isAdmin){ - Draw.color(color); - float s = 3f; - Draw.rect("icon-admin-small", x + layout.width/2f + 2 + 1, y + 7f, s, s); - } - - Draw.reset(); - Pools.free(layout); - Draw.tscl(fontScale); - } - - /**Draw all current build requests. Does not draw the beam effect, only the positions.*/ - public void drawBuildRequests(){ - synchronized (getPlaceQueue()) { - for (BuildRequest request : getPlaceQueue()) { - - if (request.remove) { - Block block = world.tile(request.x, request.y).target().block(); - - //draw removal request - Draw.color(Palette.remove); - - Lines.stroke((1f - request.progress)); - - Lines.poly(request.x * tilesize + block.offset(), - request.y * tilesize + block.offset(), - 4, block.size * tilesize / 2f, 45 + 15); - } else { - //draw place request - Draw.color(Palette.accent); - - Lines.stroke((1f - request.progress)); - - Lines.poly(request.x * tilesize + request.recipe.result.offset(), - request.y * tilesize + request.recipe.result.offset(), - 4, request.recipe.result.size * tilesize / 2f, 45 + 15); - } - } - - Draw.reset(); - } - } - - //endregion - - //region update methods - - @Override - public void update(){ - hitTime = Math.max(0f, hitTime - Timers.delta()); - - if(isDead()){ - isBoosting = false; - boostHeat = 0f; - updateRespawning(); - return; - }else{ - spawner = -1; - } - - if(!isLocal){ - interpolate(); - updateBuilding(this); //building happens even with non-locals - status.update(this); //status effect updating also happens with non locals for effect purposes - - if(getCarrier() != null){ - x = getCarrier().getX(); - y = getCarrier().getY(); - } - - if(Net.server()){ - updateShooting(); //server simulates player shooting - } - return; - } - - if(mobile){ - updateFlying(); - }else{ - updateMech(); - } - - avoidOthers(8f); - - if(!isShooting()) { - updateBuilding(this); - } - - x = Mathf.clamp(x, 0, world.width() * tilesize); - y = Mathf.clamp(y, 0, world.height() * tilesize); - } - - protected void updateMech(){ - Tile tile = world.tileWorld(x, y); - - //if player is in solid block - if(!mech.flying && tile != null && tile.solid() && !noclip) { - damage(health + 1); //die instantly - } - - if(ui.chatfrag.chatOpen()) return; - - float speed = isBoosting && !mech.flying ? debug ? 5f : mech.boostSpeed : mech.speed; - //fraction of speed when at max load - float carrySlowdown = 0.7f; - - speed *= ((inventory.hasItem() ? Mathf.lerp(1f, carrySlowdown, (float)inventory.getItem().amount/inventory.capacity()) : 1f)); - - if(mech.flying){ - //prevent strafing backwards, have a penalty for doing so - float angDist = Angles.angleDist(rotation, velocity.angle()) / 180f; - float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x - speed *= Mathf.lerp(1f, penalty, angDist); - } - - //drop from carrier on key press - if(Inputs.keyTap("drop_unit")){ - if(!mech.flying) { - if (getCarrier() != null) { - CallEntity.dropSelf(this); - } - }else if(getCarry() != null){ - dropCarry(); - }else{ - Unit unit = Units.getClosest(team, x, y, 8f, - u -> !u.isFlying() && u.getMass() <= mech.carryWeight); - - if(unit != null){ - carry(unit); - } - } - } - - movement.setZero(); - - String section = control.input(playerIndex).section; - - float xa = Inputs.getAxis(section, "move_x"); - float ya = Inputs.getAxis(section, "move_y"); - - movement.y += ya*speed; - movement.x += xa*speed; - - Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(), - Vars.control.input(playerIndex).getMouseY()); - pointerX = vec.x; - pointerY = vec.y; - updateShooting(); - - movement.limit(speed); - - if(getCarrier() == null){ - velocity.add(movement); - float prex = x, prey = y; - updateVelocityStatus(mech.drag, 10f); - moved = distanceTo(prex, prey) > 0.01f; - }else{ - velocity.setZero(); - x = Mathf.lerpDelta(x, getCarrier().getX(), 0.1f); - y = Mathf.lerpDelta(y, getCarrier().getY(), 0.1f); - } - - if(!isShooting()){ - if(!movement.isZero()) { - rotation = Mathf.slerpDelta(rotation, movement.angle(), 0.13f); - } - }else{ - float angle = control.input(playerIndex).mouseAngle(x, y); - this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f); - } - } - - protected void updateShooting(){ - if(isShooting()){ - mech.weapon.update(this, pointerX, pointerY); - } - } - - protected void updateFlying(){ - if(Units.invalidateTarget(target, this)){ - target = null; - } - - float targetX = Core.camera.position.x, targetY = Core.camera.position.y; - float attractDst = 15f; - - if(moveTarget != null && !moveTarget.isDead()){ - targetX = moveTarget.getX(); - targetY = moveTarget.getY(); - attractDst = 0f; - - if(distanceTo(moveTarget) < 2f){ - if(moveTarget instanceof CarriableTrait){ - carry((CarriableTrait) moveTarget); - }else if(moveTarget instanceof TileEntity && ((TileEntity) moveTarget).tile.block() instanceof MechFactory){ - Tile tile = ((TileEntity) moveTarget).tile; - tile.block().tapped(tile, this); - } - - moveTarget = null; - } - }else{ - moveTarget = null; - } - - movement.set(targetX - x, targetY - y).limit(mech.speed); - movement.setAngle(Mathf.slerpDelta(movement.angle(), velocity.angle(), 0.05f)); - - if(distanceTo(targetX, targetY) < attractDst){ - movement.setZero(); - } - - velocity.add(movement); - updateVelocityStatus(mech.drag, mech.maxSpeed); - - //hovering effect - x += Mathf.sin(Timers.time() + id * 999, 25f, 0.08f); - y += Mathf.cos(Timers.time() + id * 999, 25f, 0.08f); - - if(velocity.len() <= 0.2f){ - rotation += Mathf.sin(Timers.time() + id * 99, 10f, 1f); - }else{ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len()/10f); - } - - //update shooting if not building, not mining and there's ammo left - if(!isBuilding() && inventory.hasAmmo() && getMineTile() == null){ - - //autofire: mobile only! - if(mobile) { - - if (target == null) { - isShooting = false; - target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange()); - } else if(target.isValid()){ - //rotate toward and shoot the target - rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); - - Vector2 intercept = - Predict.intercept(x, y, target.getX(), target.getY(), target.getVelocity().x - velocity.x, target.getVelocity().y - velocity.y, inventory.getAmmo().bullet.speed); - - pointerX = intercept.x; - pointerY = intercept.y; - - updateShooting(); - isShooting = true; - } - - }else if(isShooting()){ - Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(), - Vars.control.input(playerIndex).getMouseY()); - pointerX = vec.x; - pointerY = vec.y; - - updateShooting(); - } - } - } - - //endregion - - //region utility methods - - public void toggleTeam(){ - team = (team == Team.blue ? Team.red : Team.blue); - } - - /**Resets all values of the player.*/ - public void reset(){ - team = Team.blue; - inventory.clear(); - placeQueue.clear(); - dead = true; - trail.clear(); - health = maxHealth(); - - add(); - } - - public boolean isShooting(){ - return isShooting && inventory.hasAmmo() && (!isBoosting || mech.flying); - } - - public void updateRespawning(){ - - if (spawner != -1 && world.tile(spawner) != null && world.tile(spawner).entity instanceof SpawnerTrait) { - ((SpawnerTrait) world.tile(spawner).entity).updateSpawning(this); - }else{ - CoreEntity entity = (CoreEntity)getClosestCore(); - if(entity != null){ - this.spawner = entity.tile.id(); - } - } - } - - public void beginRespawning(SpawnerTrait spawner){ - this.spawner = spawner.getTile().packedPosition(); - this.dead = true; - } - - @Override - public Queue getPlaceQueue(){ - return placeQueue; - } + GlyphLayout layout = Pools.obtain(GlyphLayout.class); + + Draw.tscl(0.25f / 2); + layout.setText(Core.font, name); + Draw.color(0f, 0f, 0f, 0.3f); + Draw.rect("blank", x, y + 8 - layout.height / 2, layout.width + 2, layout.height + 2); + Draw.color(); + Draw.tcolor(color); + Draw.text(name, x, y + 8); + + if(isAdmin){ + Draw.color(color); + float s = 3f; + Draw.rect("icon-admin-small", x + layout.width / 2f + 2 + 1, y + 7f, s, s); + } + + Draw.reset(); + Pools.free(layout); + Draw.tscl(fontScale); + } + + /** + * Draw all current build requests. Does not draw the beam effect, only the positions. + */ + public void drawBuildRequests(){ + synchronized(getPlaceQueue()){ + for(BuildRequest request : getPlaceQueue()){ + + if(request.remove){ + Block block = world.tile(request.x, request.y).target().block(); + + //draw removal request + Draw.color(Palette.remove); + + Lines.stroke((1f - request.progress)); + + Lines.poly(request.x * tilesize + block.offset(), + request.y * tilesize + block.offset(), + 4, block.size * tilesize / 2f, 45 + 15); + }else{ + //draw place request + Draw.color(Palette.accent); + + Lines.stroke((1f - request.progress)); + + Lines.poly(request.x * tilesize + request.recipe.result.offset(), + request.y * tilesize + request.recipe.result.offset(), + 4, request.recipe.result.size * tilesize / 2f, 45 + 15); + } + } + + Draw.reset(); + } + } + + //endregion + + //region update methods @Override - public String toString() { + public void update(){ + hitTime = Math.max(0f, hitTime - Timers.delta()); + + if(isDead()){ + isBoosting = false; + boostHeat = 0f; + updateRespawning(); + return; + }else{ + spawner = -1; + } + + if(!isLocal){ + interpolate(); + updateBuilding(this); //building happens even with non-locals + status.update(this); //status effect updating also happens with non locals for effect purposes + + if(getCarrier() != null){ + x = getCarrier().getX(); + y = getCarrier().getY(); + } + + if(Net.server()){ + updateShooting(); //server simulates player shooting + } + return; + } + + if(mobile){ + updateFlying(); + }else{ + updateMech(); + } + + if(isLocal){ + avoidOthers(8f); + } + + if(!isShooting()){ + updateBuilding(this); + } + + x = Mathf.clamp(x, 0, world.width() * tilesize); + y = Mathf.clamp(y, 0, world.height() * tilesize); + } + + protected void updateMech(){ + Tile tile = world.tileWorld(x, y); + + //if player is in solid block + if(!mech.flying && tile != null && tile.solid() && !noclip){ + damage(health + 1); //die instantly + } + + float speed = isBoosting && !mech.flying ? debug ? 5f : mech.boostSpeed : mech.speed; + //fraction of speed when at max load + float carrySlowdown = 0.7f; + + speed *= ((inventory.hasItem() ? Mathf.lerp(1f, carrySlowdown, (float) inventory.getItem().amount / inventory.capacity()) : 1f)); + + if(mech.flying){ + //prevent strafing backwards, have a penalty for doing so + float angDist = Angles.angleDist(rotation, velocity.angle()) / 180f; + float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x + speed *= Mathf.lerp(1f, penalty, angDist); + } + + //drop from carrier on key press + if(!ui.chatfrag.chatOpen() && Inputs.keyTap("drop_unit")){ + if(!mech.flying){ + if(getCarrier() != null){ + CallEntity.dropSelf(this); + } + }else if(getCarry() != null){ + dropCarry(); + }else{ + Unit unit = Units.getClosest(team, x, y, 8f, + u -> !u.isFlying() && u.getMass() <= mech.carryWeight); + + if(unit != null){ + carry(unit); + } + } + } + + movement.setZero(); + + String section = control.input(playerIndex).section; + + float xa = Inputs.getAxis(section, "move_x"); + float ya = Inputs.getAxis(section, "move_y"); + + movement.y += ya * speed; + movement.x += xa * speed; + + Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(), + Vars.control.input(playerIndex).getMouseY()); + pointerX = vec.x; + pointerY = vec.y; + updateShooting(); + + movement.limit(speed * Timers.delta()); + + if(getCarrier() == null){ + if(!ui.chatfrag.chatOpen()){ + velocity.add(movement); + } + float prex = x, prey = y; + updateVelocityStatus(mech.drag, 10f); + moved = distanceTo(prex, prey) > 0.01f; + }else{ + velocity.setZero(); + x = Mathf.lerpDelta(x, getCarrier().getX(), 0.1f); + y = Mathf.lerpDelta(y, getCarrier().getY(), 0.1f); + } + + if(!ui.chatfrag.chatOpen()){ + if(!isShooting()){ + if(!movement.isZero()){ + rotation = Mathf.slerpDelta(rotation, movement.angle(), 0.13f); + } + }else{ + float angle = control.input(playerIndex).mouseAngle(x, y); + this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f); + } + } + } + + protected void updateShooting(){ + if(isShooting()){ + mech.weapon.update(this, pointerX, pointerY); + } + } + + protected void updateFlying(){ + if(Units.invalidateTarget(target, this)){ + target = null; + } + + float targetX = Core.camera.position.x, targetY = Core.camera.position.y; + float attractDst = 15f; + + if(moveTarget != null && !moveTarget.isDead()){ + targetX = moveTarget.getX(); + targetY = moveTarget.getY(); + attractDst = 0f; + + if(distanceTo(moveTarget) < 2f){ + if(moveTarget instanceof CarriableTrait){ + carry((CarriableTrait) moveTarget); + }else if(moveTarget instanceof TileEntity && ((TileEntity) moveTarget).tile.block() instanceof MechFactory){ + Tile tile = ((TileEntity) moveTarget).tile; + tile.block().tapped(tile, this); + } + + moveTarget = null; + } + }else{ + moveTarget = null; + } + + movement.set(targetX - x, targetY - y).limit(mech.speed); + movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f)); + + if(distanceTo(targetX, targetY) < attractDst){ + movement.setZero(); + } + + velocity.add(movement); + + if(velocity.len() <= 0.2f){ + rotation += Mathf.sin(Timers.time() + id * 99, 10f, 1f); + }else{ + rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len() / 10f); + } + + updateVelocityStatus(mech.drag, mech.maxSpeed); + + //hovering effect + x += Mathf.sin(Timers.time() + id * 999, 25f, 0.08f); + y += Mathf.cos(Timers.time() + id * 999, 25f, 0.08f); + + //update shooting if not building, not mining and there's ammo left + if(!isBuilding() && inventory.hasAmmo() && getMineTile() == null){ + + //autofire: mobile only! + if(mobile){ + + if(target == null){ + isShooting = false; + target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange()); + }else if(target.isValid()){ + //rotate toward and shoot the target + rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); + + Vector2 intercept = + Predict.intercept(x, y, target.getX(), target.getY(), target.getVelocity().x - velocity.x, target.getVelocity().y - velocity.y, inventory.getAmmo().bullet.speed); + + pointerX = intercept.x; + pointerY = intercept.y; + + updateShooting(); + isShooting = true; + } + + }else if(isShooting()){ + Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(), + Vars.control.input(playerIndex).getMouseY()); + pointerX = vec.x; + pointerY = vec.y; + + updateShooting(); + } + } + } + + //endregion + + //region utility methods + + public void toggleTeam(){ + team = (team == Team.blue ? Team.red : Team.blue); + } + + /** + * Resets all values of the player. + */ + public void reset(){ + status.clear(); + team = Team.blue; + inventory.clear(); + placeQueue.clear(); + dead = true; + trail.clear(); + health = maxHealth(); + mech = (mobile ? Mechs.starterMobile : Mechs.starterDesktop); + placeQueue.clear(); + + add(); + } + + public boolean isShooting(){ + return isShooting && inventory.hasAmmo() && (!isBoosting || mech.flying); + } + + public void updateRespawning(){ + + if(spawner != -1 && world.tile(spawner) != null && world.tile(spawner).entity instanceof SpawnerTrait){ + ((SpawnerTrait) world.tile(spawner).entity).updateSpawning(this); + }else{ + CoreEntity entity = (CoreEntity) getClosestCore(); + if(entity != null){ + this.spawner = entity.tile.id(); + } + } + } + + public void beginRespawning(SpawnerTrait spawner){ + this.spawner = spawner.getTile().packedPosition(); + this.dead = true; + } + + @Override + public Queue getPlaceQueue(){ + return placeQueue; + } + + @Override + public String toString(){ return "Player{" + id + ", mech=" + mech.name + ", local=" + isLocal + ", " + x + ", " + y + "}\n"; } @@ -699,83 +717,84 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra //region read and write methods - @Override - public void writeSave(DataOutput stream) throws IOException { - stream.writeBoolean(isLocal); + @Override + public void writeSave(DataOutput stream) throws IOException{ + stream.writeBoolean(isLocal); - if(isLocal){ - stream.writeByte(mech.id); - stream.writeByte(playerIndex); - super.writeSave(stream, false); - } - } + if(isLocal){ + stream.writeByte(mech.id); + stream.writeByte(playerIndex); + super.writeSave(stream, false); + } + } - @Override - public void readSave(DataInput stream) throws IOException { - boolean local = stream.readBoolean(); + @Override + public void readSave(DataInput stream) throws IOException{ + boolean local = stream.readBoolean(); - if(local && !headless){ - byte mechid = stream.readByte(); - int index = stream.readByte(); - players[index].readSaveSuper(stream); - players[index].mech = Upgrade.getByID(mechid); - players[index].dead = false; - }else if(local){ - byte mechid = stream.readByte(); - stream.readByte(); - readSaveSuper(stream); - mech = Upgrade.getByID(mechid); - dead = false; - } - } + if(local && !headless){ + byte mechid = stream.readByte(); + int index = stream.readByte(); + players[index].readSaveSuper(stream); + players[index].mech = Upgrade.getByID(mechid); + players[index].dead = false; + }else if(local){ + byte mechid = stream.readByte(); + stream.readByte(); + readSaveSuper(stream); + mech = Upgrade.getByID(mechid); + dead = false; + } + } - private void readSaveSuper(DataInput stream) throws IOException { - super.readSave(stream); + private void readSaveSuper(DataInput stream) throws IOException{ + super.readSave(stream); - add(); - } + add(); + } - @Override - public void write(DataOutput buffer) throws IOException { - super.writeSave(buffer, !isLocal); - buffer.writeUTF(name); //TODO writing strings is very inefficient - buffer.writeBoolean(isAdmin); - buffer.writeInt(Color.rgba8888(color)); - buffer.writeBoolean(dead); - buffer.writeByte(mech.id); - buffer.writeBoolean(isBoosting); - buffer.writeInt(mining == null ? -1 : mining.packedPosition()); - buffer.writeInt(spawner); + @Override + public void write(DataOutput buffer) throws IOException{ + super.writeSave(buffer, !isLocal); + buffer.writeUTF(name); //TODO writing strings is very inefficient + buffer.writeByte(Bits.toByte(isAdmin) | (Bits.toByte(dead) << 1) | (Bits.toByte(isBoosting) << 2)); + buffer.writeInt(Color.rgba8888(color)); + buffer.writeByte(mech.id); + buffer.writeInt(mining == null ? -1 : mining.packedPosition()); + buffer.writeInt(spawner); + buffer.writeShort((short) (baseRotation * 2)); - writeBuilding(buffer); - } + writeBuilding(buffer); + } - @Override - public void read(DataInput buffer, long time) throws IOException { - float lastx = x, lasty = y, lastrot = rotation; - super.readSave(buffer); - name = buffer.readUTF(); - isAdmin = buffer.readBoolean(); - color.set(buffer.readInt()); - dead = buffer.readBoolean(); - mech = Upgrade.getByID(buffer.readByte()); - boolean boosting = buffer.readBoolean(); - int mine = buffer.readInt(); - spawner = buffer.readInt(); + @Override + public void read(DataInput buffer, long time) throws IOException{ + float lastx = x, lasty = y, lastrot = rotation; + super.readSave(buffer); + name = buffer.readUTF(); + byte bools = buffer.readByte(); + isAdmin = (bools & 1) != 0; + dead = (bools & 2) != 0; + boolean boosting = (bools & 4) != 0; + color.set(buffer.readInt()); + mech = Upgrade.getByID(buffer.readByte()); + int mine = buffer.readInt(); + spawner = buffer.readInt(); + float baseRotation = buffer.readShort() / 2f; - readBuilding(buffer, !isLocal); + readBuilding(buffer, !isLocal); - interpolator.read(lastx, lasty, x, y, time, rotation); - rotation = lastrot; + interpolator.read(lastx, lasty, x, y, time, rotation, baseRotation); + rotation = lastrot; - if(isLocal){ - x = lastx; - y = lasty; - }else{ - mining = world.tile(mine); - isBoosting = boosting; - } - } + if(isLocal){ + x = lastx; + y = lasty; + }else{ + mining = world.tile(mine); + isBoosting = boosting; + } + } - //endregion + //endregion } diff --git a/core/src/io/anuke/mindustry/entities/Predict.java b/core/src/io/anuke/mindustry/entities/Predict.java index ba27f50426..06f86b540c 100644 --- a/core/src/io/anuke/mindustry/entities/Predict.java +++ b/core/src/io/anuke/mindustry/entities/Predict.java @@ -4,12 +4,16 @@ import com.badlogic.gdx.math.Vector2; import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.ucore.util.Mathf; -/**Class for predicting shoot angles based on velocities of targets.*/ -public class Predict { +/** + * Class for predicting shoot angles based on velocities of targets. + */ +public class Predict{ private static Vector2 vec = new Vector2(); private static Vector2 vresult = new Vector2(); - /**Calculates of intercept of a stationary and moving target. Do not call from multiple threads! + /** + * Calculates of intercept of a stationary and moving target. Do not call from multiple threads! + * * @param srcx X of shooter * @param srcy Y of shooter * @param dstx X of target @@ -17,52 +21,55 @@ public class Predict { * @param dstvx X velocity of target (subtract shooter X velocity if needed) * @param dstvy Y velocity of target (subtract shooter Y velocity if needed) * @param v speed of bullet - * @return the intercept location*/ - public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v) { + * @return the intercept location + */ + public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v){ float tx = dstx - srcx, ty = dsty - srcy; // Get quadratic equation components - float a = dstvx * dstvx + dstvy * dstvy - v*v; + float a = dstvx * dstvx + dstvy * dstvy - v * v; float b = 2 * (dstvx * tx + dstvy * ty); - float c = tx*tx + ty*ty; + float c = tx * tx + ty * ty; // Solve quadratic Vector2 ts = quad(a, b, c); // Find smallest positive solution Vector2 sol = vresult.set(0, 0); - if (ts != null) { + if(ts != null){ float t0 = ts.x, t1 = ts.y; float t = Math.min(t0, t1); - if (t < 0) t = Math.max(t0, t1); - if (t > 0) { - sol.set(dstx + dstvx*t, dsty + dstvy*t); + if(t < 0) t = Math.max(t0, t1); + if(t > 0){ + sol.set(dstx + dstvx * t, dsty + dstvy * t); } } return sol; } - /**See {@link #intercept(float, float, float, float, float, float, float)}.*/ - public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v) { + /** + * See {@link #intercept(float, float, float, float, float, float, float)}. + */ + public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){ return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v); } - private static Vector2 quad(float a, float b, float c) { + private static Vector2 quad(float a, float b, float c){ Vector2 sol = null; - if (Math.abs(a) < 1e-6) { - if (Math.abs(b) < 1e-6) { - sol = Math.abs(c) < 1e-6 ? vec.set(0,0) : null; - } else { - vec.set(-c/b, -c/b); + if(Math.abs(a) < 1e-6){ + if(Math.abs(b) < 1e-6){ + sol = Math.abs(c) < 1e-6 ? vec.set(0, 0) : null; + }else{ + vec.set(-c / b, -c / b); } - } else { - float disc = b*b - 4*a*c; - if (disc >= 0) { + }else{ + float disc = b * b - 4 * a * c; + if(disc >= 0){ disc = Mathf.sqrt(disc); - a = 2*a; - sol = vec.set((-b-disc)/a, (-b+disc)/a); + a = 2 * a; + sol = vec.set((-b - disc) / a, (-b + disc) / a); } } return sol; diff --git a/core/src/io/anuke/mindustry/entities/StatusController.java b/core/src/io/anuke/mindustry/entities/StatusController.java index 374c009258..fe2e9e6248 100644 --- a/core/src/io/anuke/mindustry/entities/StatusController.java +++ b/core/src/io/anuke/mindustry/entities/StatusController.java @@ -12,7 +12,9 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -/**Class for controlling status effects on an entity.*/ +/** + * Class for controlling status effects on an entity. + */ public class StatusController implements Saveable{ private static final StatusEntry globalResult = new StatusEntry(); private static final Array removals = new ThreadArray<>(); @@ -26,20 +28,20 @@ public class StatusController implements Saveable{ public void handleApply(Unit unit, StatusEffect effect, float intensity){ if(effect == StatusEffects.none) return; //don't apply empty effects - float newTime = effect.baseDuration*intensity; + float newTime = effect.baseDuration * intensity; if(statuses.size > 0){ //check for opposite effects for(StatusEntry entry : statuses){ //extend effect - if(entry.effect == effect) { + if(entry.effect == effect){ entry.time = Math.max(entry.time, newTime); return; }else if(entry.effect.isOpposite(effect)){ //find opposite entry.effect.getTransition(unit, effect, entry.time, newTime, globalResult); entry.time = globalResult.time; - if (globalResult.effect != entry.effect) { + if(globalResult.effect != entry.effect){ entry.effect.onTransition(unit, globalResult.effect); entry.effect = globalResult.effect; } @@ -94,7 +96,7 @@ public class StatusController implements Saveable{ return damageMultiplier; } - public float getArmorMultiplier() { + public float getArmorMultiplier(){ return armorMultiplier; } @@ -106,24 +108,24 @@ public class StatusController implements Saveable{ } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ stream.writeByte(statuses.size); for(StatusEntry entry : statuses){ stream.writeByte(entry.effect.id); - stream.writeShort((short)(entry.time * 2)); + stream.writeShort((short) (entry.time * 2)); } } @Override - public void readSave(DataInput stream) throws IOException { - for (StatusEntry effect : statuses){ + public void readSave(DataInput stream) throws IOException{ + for(StatusEntry effect : statuses){ Pooling.free(effect); } statuses.clear(); byte amount = stream.readByte(); - for (int i = 0; i < amount; i++) { + for(int i = 0; i < amount; i++){ byte id = stream.readByte(); float time = stream.readShort() / 2f; StatusEntry entry = Pooling.obtain(StatusEntry.class); @@ -132,7 +134,7 @@ public class StatusController implements Saveable{ } } - public static class StatusEntry { + public static class StatusEntry{ public StatusEffect effect; public float time; diff --git a/core/src/io/anuke/mindustry/entities/TileEntity.java b/core/src/io/anuke/mindustry/entities/TileEntity.java index e53425605f..d4695604dc 100644 --- a/core/src/io/anuke/mindustry/entities/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/TileEntity.java @@ -1,6 +1,9 @@ package io.anuke.mindustry.entities; +import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectSet; import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.Remote; import io.anuke.mindustry.content.fx.Fx; @@ -10,11 +13,14 @@ import io.anuke.mindustry.game.Team; import io.anuke.mindustry.gen.CallBlocks; import io.anuke.mindustry.net.In; import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Wall; -import io.anuke.mindustry.world.blocks.modules.InventoryModule; -import io.anuke.mindustry.world.blocks.modules.LiquidModule; -import io.anuke.mindustry.world.blocks.modules.PowerModule; +import io.anuke.mindustry.world.consumers.Consume; +import io.anuke.mindustry.world.modules.ConsumeModule; +import io.anuke.mindustry.world.modules.InventoryModule; +import io.anuke.mindustry.world.modules.LiquidModule; +import io.anuke.mindustry.world.modules.PowerModule; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.EntityGroup; @@ -29,153 +35,219 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tileGroup; import static io.anuke.mindustry.Vars.world; -public class TileEntity extends BaseEntity implements TargetTrait { - public static final float timeToSleep = 60f*4; //4 seconds to fall asleep - /**This value is only used for debugging.*/ - public static int sleepingEntities = 0; +public class TileEntity extends BaseEntity implements TargetTrait{ + public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep + private static final ObjectSet tmpTiles = new ObjectSet<>(); + /** + * This value is only used for debugging. + */ + public static int sleepingEntities = 0; + public Tile tile; + public Timer timer; + public float health; - public Tile tile; - public Timer timer; - public float health; + public PowerModule power; + public InventoryModule items; + public LiquidModule liquids; + public ConsumeModule cons; - public PowerModule power; - public InventoryModule items; - public LiquidModule liquids; + /**List of (cached) tiles with entities in proximity, used for outputting to*/ + private Array proximity = new Array<>(8); + private boolean dead = false; + private boolean sleeping; + private float sleepTime; - private boolean dead = false; - private boolean sleeping; - private float sleepTime; - - /**Sets this tile entity data to this tile, and adds it if necessary.*/ - public TileEntity init(Tile tile, boolean added){ - this.tile = tile; - x = tile.drawx(); - y = tile.drawy(); + @Remote(called = Loc.server, in = In.blocks) + public static void onTileDamage(Tile tile, float health){ + if(tile.entity != null){ + tile.entity.health = health; + } + } - health = tile.block().health; - - timer = new Timer(tile.block().timers); - - if(added){ - //if(!tile.block().autoSleep) { //TODO only autosleep when creating a fresh block! - add(); - /*}else{ - sleeping = true; - sleepingEntities ++; - }*/ - } - - return this; - } + @Remote(called = Loc.server, in = In.blocks) + public static void onTileDestroyed(Tile tile){ + if(tile.entity == null) return; + tile.entity.onDeath(); + } - /**Call when nothing is happening to the entity. - * This increments the internal sleep timer.*/ - public void sleep(){ - sleepTime += Timers.delta(); - if(!sleeping && sleepTime >= timeToSleep){ - remove(); - sleeping = true; - sleepingEntities ++; - } - } + /**Sets this tile entity data to this tile, and adds it if necessary.*/ + public TileEntity init(Tile tile, boolean added){ + this.tile = tile; + x = tile.drawx(); + y = tile.drawy(); - /**Call when something just happened to the entity. - * If the entity was sleeping, this enables it. This also resets the sleep timer.*/ - public void wakeUp(){ - sleepTime = 0f; - if(sleeping){ - add(); - sleeping = false; - sleepingEntities --; - } - } + health = tile.block().health; - public boolean isSleeping(){ - return sleeping; - } + timer = new Timer(tile.block().timers); - public boolean isDead() { - return dead; - } + if(added){ + add(); + } - public void write(DataOutputStream stream) throws IOException{} - public void read(DataInputStream stream) throws IOException{} + return this; + } - private void onDeath(){ - if(!dead) { - dead = true; - Block block = tile.block(); + /** + * Call when nothing is happening to the entity. + * This increments the internal sleep timer. + */ + public void sleep(){ + sleepTime += Timers.delta(); + if(!sleeping && sleepTime >= timeToSleep){ + remove(); + sleeping = true; + sleepingEntities++; + } + } - block.onDestroyed(tile); - world.removeBlock(tile); - block.afterDestroyed(tile, this); - remove(); - } - } + /** + * Call when something just happened to the entity. + * If the entity was sleeping, this enables it. This also resets the sleep timer. + */ + public void wakeUp(){ + sleepTime = 0f; + if(sleeping){ + add(); + sleeping = false; + sleepingEntities--; + } + } - public boolean collide(Bullet other){ - return true; - } - - public void collision(Bullet other){ - tile.block().handleBulletHit(this, other); - } - - public void damage(float damage){ - if(dead) return; + public boolean isSleeping(){ + return sleeping; + } - CallBlocks.onTileDamage(tile, health - tile.block().handleDamage(tile, damage)); + public boolean isDead(){ + return dead; + } - if(health <= 0){ - CallBlocks.onTileDestroyed(tile); - } - } + public void write(DataOutputStream stream) throws IOException{ + } - public Tile getTile(){ - return tile; - } + public void read(DataInputStream stream) throws IOException{ + } - @Override - public Team getTeam() { - return tile.getTeam(); - } + private void onDeath(){ + if(!dead){ + dead = true; + Block block = tile.block(); - @Override - public Vector2 getVelocity() { - return Vector2.Zero; - } + block.onDestroyed(tile); + world.removeBlock(tile); + block.afterDestroyed(tile, this); + remove(); + } + } - @Override - public void update(){ - synchronized (Tile.tileSetLock) { - //TODO better smoke effect, this one is awful - if (health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) && - Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))) { + public boolean collide(Bullet other){ + return true; + } - Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4)); - } + public void collision(Bullet other){ + tile.block().handleBulletHit(this, other); + } - if (health <= 0) { - onDeath(); - } + public void damage(float damage){ + if(dead) return; - tile.block().update(tile); - } - } + CallBlocks.onTileDamage(tile, health - tile.block().handleDamage(tile, damage)); - @Override - public EntityGroup targetGroup() { - return tileGroup; - } + if(health <= 0){ + CallBlocks.onTileDestroyed(tile); + } + } - @Remote(called = Loc.server, in = In.blocks) - public static void onTileDamage(Tile tile, float health){ - tile.entity.health = health; - } + public Tile getTile(){ + return tile; + } - @Remote(called = Loc.server, in = In.blocks) - public static void onTileDestroyed(Tile tile){ - if(tile.entity == null) return; - tile.entity.onDeath(); - } + public boolean consumed(Class type){ + return tile.block().consumes.get(type).valid(tile.block(), this); + } + + public void removeFromProximity(){ + GridPoint2[] nearby = Edges.getEdges(tile.block().size); + for(GridPoint2 point : nearby){ + Tile other = world.tile(tile.x + point.x, tile.y + point.y); + //remove this tile from all nearby tile's proximities + if(other != null){ + other = other.target(); + other.block().onProximityUpdate(other); + } + if(other != null && other.entity != null){ + other.entity.proximity.removeValue(tile, true); + } + } + } + + public void updateProximity(){ + tmpTiles.clear(); + proximity.clear(); + + GridPoint2[] nearby = Edges.getEdges(tile.block().size); + for(GridPoint2 point : nearby){ + Tile other = world.tile(tile.x + point.x, tile.y + point.y); + + if(other != null){ + other.block().onProximityUpdate(other); + other = other.target(); + } + + if(other != null && other.entity != null){ + tmpTiles.add(other); + + //add this tile to proximity of nearby tiles + if(!other.entity.proximity.contains(tile, true)){ + other.entity.proximity.add(tile); + } + } + } + + //using a set to prevent duplicates + for(Tile tile : tmpTiles){ + proximity.add(tile); + } + + tile.block().onProximityUpdate(tile); + } + + public Array proximity(){ + return proximity; + } + + @Override + public Team getTeam(){ + return tile.getTeam(); + } + + @Override + public Vector2 getVelocity(){ + return Vector2.Zero; + } + + @Override + public void update(){ + synchronized(Tile.tileSetLock){ + //TODO better smoke effect, this one is awful + if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) && + Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){ + + Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4)); + } + + if(health <= 0){ + onDeath(); + } + + tile.block().update(tile); + if(cons != null){ + cons.update(this); + } + } + } + + @Override + public EntityGroup targetGroup(){ + return tileGroup; + } } diff --git a/core/src/io/anuke/mindustry/entities/Unit.java b/core/src/io/anuke/mindustry/entities/Unit.java index 4808b740a4..8ad6360042 100644 --- a/core/src/io/anuke/mindustry/entities/Unit.java +++ b/core/src/io/anuke/mindustry/entities/Unit.java @@ -31,13 +31,20 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; -public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait { - /**total duration of hit flash effect*/ +public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait{ + /** + * total duration of hit flash effect + */ public static final float hitDuration = 9f; - /**Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.*/ + /** + * Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks. + */ public static final float velocityPercision = 8f; - /**Maximum absolute value of a velocity vector component.*/ - public static final float maxAbsVelocity = 127f/velocityPercision; + /** + * Maximum absolute value of a velocity vector component. + */ + public static final float maxAbsVelocity = 127f / velocityPercision; + public static final float elevationScale = 4f; private static final Vector2 moveVector = new Vector2(); @@ -52,30 +59,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ protected Vector2 velocity = new Translator(0f, 0.0001f); protected float hitTime; protected float drownTime; + protected float elevation; @Override - public UnitInventory getInventory() { + public UnitInventory getInventory(){ return inventory; } @Override - public float getRotation() { + public float getRotation(){ return rotation; } @Override - public void setRotation(float rotation) { + public void setRotation(float rotation){ this.rotation = rotation; } @Override - public void setCarrier(CarryTrait carrier) { - this.carrier = carrier; + public CarryTrait getCarrier(){ + return carrier; } @Override - public CarryTrait getCarrier() { - return carrier; + public void setCarrier(CarryTrait carrier){ + this.carrier = carrier; } @Override @@ -84,7 +92,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } @Override - public void interpolate() { + public void interpolate(){ interpolator.update(); x = interpolator.pos.x; @@ -96,7 +104,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } @Override - public Interpolator getInterpolator() { + public Interpolator getInterpolator(){ return interpolator; } @@ -113,31 +121,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } @Override - public void onDeath() { + public void onDeath(){ inventory.clear(); drownTime = 0f; status.clear(); } @Override - public Vector2 getVelocity() { + public Vector2 getVelocity(){ return velocity; } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ writeSave(stream, false); } @Override - public void readSave(DataInput stream) throws IOException { + public void readSave(DataInput stream) throws IOException{ byte team = stream.readByte(); boolean dead = stream.readBoolean(); float x = stream.readFloat(); float y = stream.readFloat(); byte xv = stream.readByte(); byte yv = stream.readByte(); - float rotation = stream.readShort()/2f; + float rotation = stream.readShort() / 2f; int health = stream.readShort(); this.status.readSave(stream); @@ -151,21 +159,21 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ this.rotation = rotation; } - public void writeSave(DataOutput stream, boolean net) throws IOException { + public void writeSave(DataOutput stream, boolean net) throws IOException{ stream.writeByte(team.ordinal()); stream.writeBoolean(isDead()); stream.writeFloat(net ? interpolator.target.x : x); stream.writeFloat(net ? interpolator.target.y : y); - stream.writeByte((byte)(Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); - stream.writeByte((byte)(Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); - stream.writeShort((short)(rotation*2)); - stream.writeShort((short)health); + stream.writeByte((byte) (Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); + stream.writeByte((byte) (Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); + stream.writeShort((short) (rotation * 2)); + stream.writeShort((short) health); status.writeSave(stream); inventory.writeSave(stream); } public float calculateDamage(float amount){ - return amount * Mathf.clamp(1f-getArmor()/100f*status.getArmorMultiplier()); + return amount * Mathf.clamp(1f - getArmor() / 100f * status.getArmorMultiplier()); } public float getDamageMultipler(){ @@ -180,7 +188,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(state.teams.has(team)){ TeamData data = state.teams.get(team); - Tile tile = Geometry.findClosest(x, y, data.cores); + Tile tile = Geometry.findClosest(x, y, data.cores); if(tile == null){ return null; }else{ @@ -198,15 +206,18 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public void avoidOthers(float avoidRange){ - EntityPhysics.getNearby(getGroup(), x, y, avoidRange*2f, t -> { - if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t)) return; + EntityPhysics.getNearby(getGroup(), x, y, avoidRange * 2f, t -> { + if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t)) + return; float dst = distanceTo(t); if(dst > avoidRange) return; velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange)))); }); } - /**Updates velocity and status effects.*/ + /** + * Updates velocity and status effects. + */ public void updateVelocityStatus(float drag, float maxVelocity){ if(isCarried()){ //carried units do not take into account velocity normally set(carrier.getX(), carrier.getY()); @@ -221,9 +232,13 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ velocity.limit(maxVelocity).scl(status.getSpeedMultiplier()); - if(isFlying()) { + if(isFlying()){ x += velocity.x / getMass() * Timers.delta(); y += velocity.y / getMass() * Timers.delta(); + + if(tile != null){ + elevation = Mathf.lerpDelta(elevation, tile.elevation, 0.04f); + } }else{ boolean onLiquid = floor.isLiquid; @@ -239,7 +254,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } } - if(onLiquid && velocity.len() > 0.4f && Timers.get(this, "flooreffect", 14 - (velocity.len() * floor.speedMultiplier)*2f)){ + if(onLiquid && velocity.len() > 0.4f && Timers.get(this, "flooreffect", 14 - (velocity.len() * floor.speedMultiplier) * 2f)){ Effects.effect(floor.walkEffect, floor.liquidColor, x, y); } @@ -250,7 +265,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } if(onLiquid && floor.drownTime > 0){ - drownTime += Timers.delta() * 1f/floor.drownTime; + drownTime += Timers.delta() * 1f / floor.drownTime; if(Timers.get(this, "drowneffect", 15)){ Effects.effect(floor.drownUpdateEffect, floor.liquidColor, x, y); } @@ -270,7 +285,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f; } - velocity.scl(Mathf.clamp(1f-drag* floor.dragMultiplier* Timers.delta())); + velocity.scl(Mathf.clamp(1f - drag * floor.dragMultiplier * Timers.delta())); } public void applyEffect(StatusEffect effect, float intensity){ @@ -293,11 +308,17 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public float getAmmoFraction(){ - return inventory.totalAmmo() / (float)inventory.ammoCapacity(); + return inventory.totalAmmo() / (float) inventory.ammoCapacity(); } - public void drawUnder(){} - public void drawOver(){} + public void drawUnder(){ + } + + public void drawOver(){ + } + + public void drawShadow(){ + } public void drawView(){ Fill.circle(x, y, getViewDistance()); @@ -312,12 +333,20 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public abstract TextureRegion getIconRegion(); + public abstract int getItemCapacity(); + public abstract int getAmmoCapacity(); + public abstract float getArmor(); + public abstract boolean acceptsAmmo(Item item); + public abstract void addAmmo(Item item); + public abstract float getMass(); + public abstract boolean isFlying(); + public abstract float getSize(); } diff --git a/core/src/io/anuke/mindustry/entities/UnitInventory.java b/core/src/io/anuke/mindustry/entities/UnitInventory.java index f4739bf99b..53fd627f88 100644 --- a/core/src/io/anuke/mindustry/entities/UnitInventory.java +++ b/core/src/io/anuke/mindustry/entities/UnitInventory.java @@ -8,16 +8,17 @@ import io.anuke.mindustry.type.AmmoType; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.ItemStack; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; public class UnitInventory implements Saveable{ + private final Unit unit; private Array ammos = new Array<>(); private int totalAmmo; private ItemStack item = new ItemStack(Items.stone, 0); - private final Unit unit; - - public UnitInventory(Unit unit) { + public UnitInventory(Unit unit){ this.unit = unit; } @@ -26,24 +27,24 @@ public class UnitInventory implements Saveable{ } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ stream.writeShort(item.amount); stream.writeByte(item.item.id); stream.writeShort(totalAmmo); stream.writeByte(ammos.size); - for(int i = 0; i < ammos.size; i ++){ + for(int i = 0; i < ammos.size; i++){ stream.writeByte(ammos.get(i).type.id); stream.writeShort(ammos.get(i).amount); } } @Override - public void readSave(DataInput stream) throws IOException { + public void readSave(DataInput stream) throws IOException{ short iamount = stream.readShort(); byte iid = stream.readByte(); this.totalAmmo = stream.readShort(); byte ammoa = stream.readByte(); - for(int i = 0; i < ammoa; i ++){ + for(int i = 0; i < ammoa; i++){ byte aid = stream.readByte(); int am = stream.readShort(); ammos.add(new AmmoEntry(AmmoType.getByID(aid), am)); @@ -53,12 +54,14 @@ public class UnitInventory implements Saveable{ item.amount = iamount; } - /**Returns ammo range, or MAX_VALUE if this inventory has no ammo.*/ + /** + * Returns ammo range, or MAX_VALUE if this inventory has no ammo. + */ public float getAmmoRange(){ return hasAmmo() ? getAmmo().getRange() : Float.MAX_VALUE; } - public AmmoType getAmmo() { + public AmmoType getAmmo(){ return ammos.size == 0 ? null : ammos.peek().type; } @@ -69,9 +72,9 @@ public class UnitInventory implements Saveable{ public void useAmmo(){ if(unit.isInfiniteAmmo()) return; AmmoEntry entry = ammos.peek(); - entry.amount --; + entry.amount--; if(entry.amount == 0) ammos.pop(); - totalAmmo --; + totalAmmo--; } public int totalAmmo(){ @@ -87,22 +90,23 @@ public class UnitInventory implements Saveable{ } public void addAmmo(AmmoType type){ + if(type == null) return; totalAmmo += type.quantityMultiplier; //find ammo entry by type - for(int i = ammos.size - 1; i >= 0; i --){ + for(int i = ammos.size - 1; i >= 0; i--){ AmmoEntry entry = ammos.get(i); //if found, put it to the right if(entry.type == type){ entry.amount += type.quantityMultiplier; - ammos.swap(i, ammos.size-1); + ammos.swap(i, ammos.size - 1); return; } } //must not be found - AmmoEntry entry = new AmmoEntry(type, (int)type.quantityMultiplier); + AmmoEntry entry = new AmmoEntry(type, (int) type.quantityMultiplier); ammos.add(entry); } diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index 86b74a1968..1b9fcb27f2 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -15,12 +15,19 @@ import io.anuke.ucore.function.Predicate; import static io.anuke.mindustry.Vars.*; -/**Utility class for unit and team interactions.*/ -public class Units { +/** + * Utility class for unit and team interactions. + */ +public class Units{ private static Rectangle rect = new Rectangle(); private static Rectangle hitrect = new Rectangle(); + private static Unit result; + private static float cdist; + private static boolean boolResult; - /**Validates a target. + /** + * Validates a target. + * * @param target The target to validate * @param team The team of the thing doing tha targeting * @param x The X position of the thing doign the targeting @@ -28,44 +35,52 @@ public class Units { * @param range The maximum distance from the target X/Y the targeter can be for it to be valid * @return whether the target is invalid */ - public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range) { + public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){ return target == null || (range != Float.MAX_VALUE && target.distanceTo(x, y) > range) || target.getTeam() == team || !target.isValid(); } - /**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/ + /** + * See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} + */ public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){ return invalidateTarget(target, team, x, y, Float.MAX_VALUE); } - /**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/ + /** + * See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} + */ public static boolean invalidateTarget(TargetTrait target, Unit targeter){ return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange()); } - /**Returns whether there are any entities on this tile.*/ + /** + * Returns whether there are any entities on this tile. + */ public static boolean anyEntities(Tile tile){ Block type = tile.block(); rect.setSize(type.size * tilesize, type.size * tilesize); rect.setCenter(tile.drawx(), tile.drawy()); - boolean[] value = new boolean[1]; + boolResult = false; Units.getNearby(rect, unit -> { - if (value[0]) return; - if (!unit.isFlying()) { + if(boolResult) return; + if(!unit.isFlying()){ unit.getHitbox(hitrect); - if (hitrect.overlaps(rect)) { - value[0] = true; + if(hitrect.overlaps(rect)){ + boolResult = true; } } }); - return value[0]; + return boolResult; } - /**Returns whether there are any entities on this tile, with the hitbox expanded.*/ + /** + * Returns whether there are any entities on this tile, with the hitbox expanded. + */ public static boolean anyEntities(Tile tile, float expansion, Predicate pred){ Block type = tile.block(); rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion); @@ -78,7 +93,7 @@ public class Units { if(!unit.isFlying()){ unit.getHitbox(hitrect); - if(hitrect.overlaps(rect)) { + if(hitrect.overlaps(rect)){ value[0] = true; } } @@ -87,7 +102,9 @@ public class Units { return value[0]; } - /**Returns the neareset ally tile in a range.*/ + /** + * Returns the neareset ally tile in a range. + */ public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate pred){ for(Team enemy : state.teams.alliesOf(team)){ TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred); @@ -98,7 +115,9 @@ public class Units { return null; } - /**Returns the neareset enemy tile in a range.*/ + /** + * Returns the neareset enemy tile in a range. + */ public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate pred){ for(Team enemy : state.teams.enemiesOf(team)){ TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred); @@ -109,7 +128,9 @@ public class Units { return null; } - /**Iterates over all units on all teams, including players.*/ + /** + * Iterates over all units on all teams, including players. + */ public static void allUnits(Consumer cons){ //check all unit groups first for(EntityGroup group : unitGroups){ @@ -126,7 +147,9 @@ public class Units { } } - /**Returns the closest target enemy. First, units are checked, then tile entities.*/ + /** + * Returns the closest target enemy. First, units are checked, then tile entities. + */ public static TargetTrait getClosestTarget(Team team, float x, float y, float range){ Unit unit = getClosestEnemy(team, x, y, range, u -> true); if(unit != null){ @@ -136,74 +159,82 @@ public class Units { } } - /**Returns the closest enemy of this team. Filter by predicate.*/ + /** + * Returns the closest enemy of this team. Filter by predicate. + */ public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate predicate){ - Unit[] result = {null}; - float[] cdist = {0}; + result = null; + cdist = 0f; - rect.setSize(range*2f).setCenter(x, y); + rect.setSize(range * 2f).setCenter(x, y); getNearbyEnemies(team, rect, e -> { - if (e.isDead() || !predicate.test(e)) + if(e.isDead() || !predicate.test(e)) return; float dist = Vector2.dst(e.x, e.y, x, y); - if (dist < range) { - if (result[0] == null || dist < cdist[0]) { - result[0] = e; - cdist[0] = dist; + if(dist < range){ + if(result == null || dist < cdist){ + result = e; + cdist = dist; } } }); - return result[0]; + return result; } - /**Returns the closest ally of this team. Filter by predicate.*/ + /** + * Returns the closest ally of this team. Filter by predicate. + */ public static Unit getClosest(Team team, float x, float y, float range, Predicate predicate){ - Unit[] result = {null}; - float[] cdist = {0}; + result = null; + cdist = 0f; - rect.setSize(range*2f).setCenter(x, y); + rect.setSize(range * 2f).setCenter(x, y); getNearby(team, rect, e -> { - if (!predicate.test(e)) + if(!predicate.test(e)) return; float dist = Vector2.dst(e.x, e.y, x, y); - if (dist < range) { - if (result[0] == null || dist < cdist[0]) { - result[0] = e; - cdist[0] = dist; + if(dist < range){ + if(result == null || dist < cdist){ + result = e; + cdist = dist; } } }); - return result[0]; + return result; } - /**Iterates over all units in a rectangle.*/ + /** + * Iterates over all units in a rectangle. + */ public static void getNearby(Team team, Rectangle rect, Consumer cons){ EntityGroup group = unitGroups[team.ordinal()]; if(!group.isEmpty()){ - EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity)); + EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity)); } //now check all players EntityPhysics.getNearby(playerGroup, rect, player -> { - if(((Unit)player).team == team) cons.accept((Unit)player); + if(((Unit) player).team == team) cons.accept((Unit) player); }); } - /**Iterates over all units in a circle around this position.*/ + /** + * Iterates over all units in a circle around this position. + */ public static void getNearby(Team team, float x, float y, float radius, Consumer cons){ rect.setSize(radius * 2).setCenter(x, y); EntityGroup group = unitGroups[team.ordinal()]; if(!group.isEmpty()){ EntityPhysics.getNearby(group, rect, entity -> { - if(entity.distanceTo(x, y) <= radius) { + if(entity.distanceTo(x, y) <= radius){ cons.accept((Unit) entity); } }); @@ -211,46 +242,52 @@ public class Units { //now check all players EntityPhysics.getNearby(playerGroup, rect, player -> { - if(((Unit)player).team == team && player.distanceTo(x, y) <= radius){ - cons.accept((Unit)player); + if(((Unit) player).team == team && player.distanceTo(x, y) <= radius){ + cons.accept((Unit) player); } }); } - /**Iterates over all units in a rectangle.*/ + /** + * Iterates over all units in a rectangle. + */ public static void getNearby(Rectangle rect, Consumer cons){ for(Team team : Team.all){ EntityGroup group = unitGroups[team.ordinal()]; if(!group.isEmpty()){ - EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity)); + EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity)); } } //now check all enemy players - EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit)player)); + EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit) player)); } - /**Iterates over all units that are enemies of this team.*/ + /** + * Iterates over all units that are enemies of this team. + */ public static void getNearbyEnemies(Team team, Rectangle rect, Consumer cons){ ObjectSet targets = state.teams.enemiesOf(team); for(Team other : targets){ EntityGroup group = unitGroups[other.ordinal()]; if(!group.isEmpty()){ - EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity)); + EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity)); } } //now check all enemy players EntityPhysics.getNearby(playerGroup, rect, player -> { - if(targets.contains(((Player)player).team)){ - cons.accept((Unit)player); + if(targets.contains(((Player) player).team)){ + cons.accept((Unit) player); } }); } - /**Iterates over all units.*/ + /** + * Iterates over all units. + */ public static void getAllUnits(Consumer cons){ for(Team team : Team.all){ diff --git a/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java index f298ab6ab4..52a1594c96 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java @@ -6,10 +6,10 @@ import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.graphics.Draw; //TODO scale velocity depending on fslope() -public class ArtilleryBulletType extends BasicBulletType { +public class ArtilleryBulletType extends BasicBulletType{ protected Effect trailEffect = BulletFx.artilleryTrail; - public ArtilleryBulletType(float speed, float damage, String bulletSprite) { + public ArtilleryBulletType(float speed, float damage, String bulletSprite){ super(speed, damage, bulletSprite); collidesTiles = false; collides = false; @@ -17,18 +17,18 @@ public class ArtilleryBulletType extends BasicBulletType { } @Override - public void update(Bullet b) { + public void update(Bullet b){ super.update(b); - if(b.timer.get(0, 3 + b.fslope()*2f)){ + if(b.timer.get(0, 3 + b.fslope() * 2f)){ Effects.effect(trailEffect, backColor, b.x, b.y, b.fslope() * 4f); } } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ float baseScale = 0.7f; - float scale = (baseScale + b.fslope()*(1f-baseScale)); + float scale = (baseScale + b.fslope() * (1f - baseScale)); float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout()); diff --git a/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java index 3822ea7f52..d5d1455eb0 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java @@ -12,8 +12,10 @@ import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; -/**A BulletType for most ammo-based bullets shot from turrets and units.*/ -public class BasicBulletType extends BulletType { +/** + * A BulletType for most ammo-based bullets shot from turrets and units. + */ +public class BasicBulletType extends BulletType{ public Color backColor = Palette.bulletYellowBack, frontColor = Palette.bulletYellow; public float bulletWidth = 5f, bulletHeight = 7f; public float bulletShrink = 0.5f; @@ -23,7 +25,9 @@ public class BasicBulletType extends BulletType { public float fragVelocityMin = 0.2f, fragVelocityMax = 1f; public BulletType fragBullet = null; - /**Use a negative value to disable splash damage.*/ + /** + * Use a negative value to disable splash damage. + */ public float splashDamageRadius = -1f; public float splashDamage = 6f; @@ -39,19 +43,19 @@ public class BasicBulletType extends BulletType { public float hitShake = 0f; - public BasicBulletType(float speed, float damage, String bulletSprite) { + public BasicBulletType(float speed, float damage, String bulletSprite){ super(speed, damage); this.bulletSprite = bulletSprite; } @Override - public void load() { + public void load(){ backRegion = Draw.region(bulletSprite + "-back"); frontRegion = Draw.region(bulletSprite); } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout()); Draw.color(backColor); @@ -62,7 +66,7 @@ public class BasicBulletType extends BulletType { } @Override - public void update(Bullet b) { + public void update(Bullet b){ super.update(b); if(homingPower > 0.0001f){ @@ -74,20 +78,20 @@ public class BasicBulletType extends BulletType { } @Override - public void hit(Bullet b, float x, float y) { + public void hit(Bullet b, float x, float y){ super.hit(b, x, y); Effects.shake(hitShake, hitShake, b); - if(fragBullet != null) { - for (int i = 0; i < fragBullets; i++) { + if(fragBullet != null){ + for(int i = 0; i < fragBullets; i++){ float len = Mathf.random(1f, 7f); float a = Mathf.random(360f); Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax)); } } - if(Mathf.chance(incendChance)) { + if(Mathf.chance(incendChance)){ Damage.createIncend(x, y, incendSpread, incendAmount); } @@ -97,7 +101,7 @@ public class BasicBulletType extends BulletType { } @Override - public void despawned(Bullet b) { + public void despawned(Bullet b){ if(fragBullet != null || splashDamageRadius > 0){ hit(b); } diff --git a/core/src/io/anuke/mindustry/entities/bullet/BombBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BombBulletType.java index 5682477e49..cdca80de79 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BombBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BombBulletType.java @@ -1,8 +1,8 @@ package io.anuke.mindustry.entities.bullet; -public class BombBulletType extends BasicBulletType { +public class BombBulletType extends BasicBulletType{ - public BombBulletType(float damage, float radius, String sprite) { + public BombBulletType(float damage, float radius, String sprite){ super(0.7f, 0, sprite); splashDamageRadius = radius; splashDamage = damage; diff --git a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java b/core/src/io/anuke/mindustry/entities/bullet/Bullet.java index 7f218d4524..0e9322928f 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java +++ b/core/src/io/anuke/mindustry/entities/bullet/Bullet.java @@ -27,198 +27,199 @@ import static io.anuke.mindustry.Vars.bulletGroup; import static io.anuke.mindustry.Vars.world; public class Bullet extends BulletEntity implements TeamTrait, SyncTrait{ - private static Vector2 vector = new Vector2(); + private static Vector2 vector = new Vector2(); + public Timer timer = new Timer(3); + private Team team; + private Object data; + private boolean supressCollision; - private Team team; - private Object data; - private boolean supressCollision; + /** + * Internal use only! + */ + public Bullet(){ + } - public Timer timer = new Timer(3); + public static void create(BulletType type, TeamTrait owner, float x, float y, float angle){ + create(type, owner, owner.getTeam(), x, y, angle); + } - public static void create (BulletType type, TeamTrait owner, float x, float y, float angle){ - create(type, owner, owner.getTeam(), x, y, angle); - } + public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle){ + create(type, owner, team, x, y, angle, 1f); + } - public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle){ - create(type, owner, team, x, y, angle, 1f); - } + public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){ + create(type, owner, team, x, y, angle, velocityScl, null); + } - public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){ - create(type, owner, team, x, y, angle, velocityScl, null); - } + public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, Object data){ + Bullet bullet = Pooling.obtain(Bullet.class); + bullet.type = type; + bullet.owner = owner; + bullet.data = data; - public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, Object data){ - Bullet bullet = Pooling.obtain(Bullet.class); - bullet.type = type; - bullet.owner = owner; - bullet.data = data; + bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl); + if(type.keepVelocity){ + bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait) owner).getVelocity() : Vector2.Zero); + } + bullet.hitbox.setSize(type.hitsize); - bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl); - if(type.keepVelocity){ - bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero); - } - bullet.hitbox.setSize(type.hitsize); + bullet.team = team; + bullet.type = type; - bullet.team = team; - bullet.type = type; + //translate bullets backwards, purely for visual reasons + float backDelta = Timers.delta(); - //translate bullets backwards, purely for visual reasons - float backDelta = Timers.delta(); + bullet.lastPosition().set(x - bullet.velocity.x * backDelta, y - bullet.velocity.y * backDelta, bullet.angle()); + bullet.setLastUpdated(TimeUtils.millis()); + bullet.setUpdateSpacing((long) ((Timers.delta() / 60f) * 1000)); + bullet.set(x - bullet.velocity.x * backDelta, y - bullet.velocity.y * backDelta); - bullet.lastPosition().set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta, bullet.angle()); - bullet.setLastUpdated(TimeUtils.millis()); - bullet.setUpdateSpacing((long)((Timers.delta() / 60f) * 1000)); - bullet.set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta); + bullet.add(); + } - bullet.add(); - } + public static void create(BulletType type, Bullet parent, float x, float y, float angle){ + create(type, parent.owner, parent.team, x, y, angle); + } - public static void create(BulletType type, Bullet parent, float x, float y, float angle){ - create(type, parent.owner, parent.team, x, y, angle); - } + public static void create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){ + create(type, parent.owner, parent.team, x, y, angle, velocityScl); + } - public static void create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){ - create(type, parent.owner, parent.team, x, y, angle, velocityScl); - } + @Remote(called = Loc.server, in = In.entities) + public static void createBullet(BulletType type, float x, float y, float angle){ + create(type, null, Team.none, x, y, angle); + } - @Remote(called = Loc.server, in = In.entities) - public static void createBullet(BulletType type, float x, float y, float angle){ - create(type, null, Team.none, x, y, angle); - } + public boolean collidesTiles(){ + return type.collidesTiles; + } - /**Internal use only!*/ - public Bullet(){} + public void supressCollision(){ + supressCollision = true; + } - public boolean collidesTiles(){ - return type.collidesTiles; - } + public void resetOwner(Entity entity, Team team){ + this.owner = entity; + this.team = team; + } - public void supressCollision(){ - supressCollision = true; - } + public void scaleTime(float add){ + time += add; + } - public void resetOwner(Entity entity, Team team){ - this.owner = entity; - this.team = team; - } + public Object getData(){ + return data; + } - public void scaleTime(float add){ - time += add; - } + @Override + public float getDamage(){ + if(owner instanceof Unit){ + return super.getDamage() * ((Unit) owner).getDamageMultipler(); + } - public Object getData() { - return data; - } + return super.getDamage(); + } - @Override - public float getDamage(){ - if(owner instanceof Unit){ - return super.getDamage() * ((Unit) owner).getDamageMultipler(); - } + @Override + public boolean isSyncing(){ + return type.syncable; + } - return super.getDamage(); - } + @Override + public void write(DataOutput data) throws IOException{ + data.writeFloat(x); + data.writeFloat(y); + data.writeFloat(velocity.x); + data.writeFloat(velocity.y); + data.writeByte(team.ordinal()); + data.writeByte(type.id); + } - @Override - public boolean isSyncing(){ - return type.syncable; - } + @Override + public void read(DataInput data, long time) throws IOException{ + x = data.readFloat(); + y = data.readFloat(); + velocity.x = data.readFloat(); + velocity.y = data.readFloat(); + team = Team.all[data.readByte()]; + type = BulletType.getByID(data.readByte()); + } - @Override - public void write(DataOutput data) throws IOException { - data.writeFloat(x); - data.writeFloat(y); - data.writeFloat(velocity.x); - data.writeFloat(velocity.y); - data.writeByte(team.ordinal()); - data.writeByte(type.id); - } + @Override + public Team getTeam(){ + return team; + } - @Override - public void read(DataInput data, long time) throws IOException{ - x = data.readFloat(); - y = data.readFloat(); - velocity.x = data.readFloat(); - velocity.y = data.readFloat(); - team = Team.all[data.readByte()]; - type = BulletType.getByID(data.readByte()); - } + @Override + public void draw(){ + type.draw(this); + } - @Override - public Team getTeam() { - return team; - } + @Override + public float drawSize(){ + return 8; + } - @Override - public void draw(){ - type.draw(this); - } + @Override + public boolean collides(SolidTrait other){ + return type.collides && super.collides(other); + } - @Override - public float drawSize(){ - return 8; - } + @Override + public void collision(SolidTrait other, float x, float y){ + super.collision(other, x, y); - @Override - public boolean collides(SolidTrait other){ - return type.collides && super.collides(other); - } + if(other instanceof Unit){ + Unit unit = (Unit) other; + unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass())); + unit.applyEffect(type.status, type.statusIntensity); + } + } - @Override - public void collision(SolidTrait other, float x, float y){ - super.collision(other, x, y); + @Override + public void update(){ + super.update(); - if(other instanceof Unit){ - Unit unit = (Unit)other; - unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass())); - unit.applyEffect(type.status, type.statusIntensity); - } - } + if(type.hitTiles && collidesTiles() && !supressCollision){ + world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> { - @Override - public void update(){ - super.update(); + Tile tile = world.tile(x, y); + if(tile == null) return false; + tile = tile.target(); - if (type.hitTiles && collidesTiles() && !supressCollision) { - world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> { + if(tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && tile.entity.tile.getTeam() != team){ + tile.entity.collision(this); - Tile tile = world.tile(x, y); - if (tile == null) return false; - tile = tile.target(); + if(!supressCollision){ + type.hit(this); + remove(); + } - if (tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && tile.entity.tile.getTeam() != team) { - tile.entity.collision(this); + return true; + } - if(!supressCollision){ - type.hit(this); - remove(); - } + return false; + }); + } - return true; - } + supressCollision = false; + } - return false; - }); - } + @Override + public void reset(){ + super.reset(); + timer.clear(); + team = null; + data = null; + } - supressCollision = false; - } + @Override + public void removed(){ + Pooling.free(this); + } - @Override - public void reset() { - super.reset(); - timer.clear(); - team = null; - data = null; - } - - @Override - public void removed() { - Pooling.free(this); - } - - @Override - public EntityGroup targetGroup() { - return bulletGroup; - } + @Override + public EntityGroup targetGroup(){ + return bulletGroup; + } } diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index e402ab00a1..d4d750035d 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -9,65 +9,83 @@ import io.anuke.ucore.core.Effects; import io.anuke.ucore.entities.impl.BaseBulletType; public abstract class BulletType extends BaseBulletType implements Content{ - private static int lastid = 0; - private static Array types = new Array<>(); + private static int lastid = 0; + private static Array types = new Array<>(); - public final int id; - /**Knockback in velocity.*/ - public float knockback; - /**Whether this bullet hits tiles.*/ - public boolean hitTiles = true; - /**Status effect applied on hit.*/ - public StatusEffect status = StatusEffects.none; - /**Intensity of applied status effect in terms of duration.*/ - public float statusIntensity = 0.5f; - /**What fraction of armor is pierced, 0-1*/ - public float armorPierce = 0f; - /**Whether to sync this bullet to clients.*/ - public boolean syncable; - /**Whether this bullet type collides with tiles.*/ - public boolean collidesTiles = true; - /**Whether this bullet types collides with anything at all.*/ - public boolean collides = true; - /**Whether velocity is inherited from the shooter.*/ - public boolean keepVelocity = true; + public final int id; + /** + * Knockback in velocity. + */ + public float knockback; + /** + * Whether this bullet hits tiles. + */ + public boolean hitTiles = true; + /** + * Status effect applied on hit. + */ + public StatusEffect status = StatusEffects.none; + /** + * Intensity of applied status effect in terms of duration. + */ + public float statusIntensity = 0.5f; + /** + * What fraction of armor is pierced, 0-1 + */ + public float armorPierce = 0f; + /** + * Whether to sync this bullet to clients. + */ + public boolean syncable; + /** + * Whether this bullet type collides with tiles. + */ + public boolean collidesTiles = true; + /** + * Whether this bullet types collides with anything at all. + */ + public boolean collides = true; + /** + * Whether velocity is inherited from the shooter. + */ + public boolean keepVelocity = true; - public BulletType(float speed, float damage){ - this.id = lastid ++; - this.speed = speed; - this.damage = damage; - lifetime = 40f; - hiteffect = BulletFx.hitBulletSmall; - despawneffect = BulletFx.despawn; + public BulletType(float speed, float damage){ + this.id = lastid++; + this.speed = speed; + this.damage = damage; + lifetime = 40f; + hiteffect = BulletFx.hitBulletSmall; + despawneffect = BulletFx.despawn; - types.add(this); - } - - @Override - public void hit(Bullet b, float hitx, float hity){ - Effects.effect(hiteffect, hitx, hity, b.angle()); - } + types.add(this); + } - @Override - public void despawned(Bullet b){ - Effects.effect(despawneffect, b.x, b.y, b.angle()); - } + public static BulletType getByID(int id){ + return types.get(id); + } - @Override - public String getContentTypeName() { - return "bullettype"; - } + public static Array all(){ + return types; + } - @Override - public Array getAll() { - return types; - } + @Override + public void hit(Bullet b, float hitx, float hity){ + Effects.effect(hiteffect, hitx, hity, b.angle()); + } - public static BulletType getByID(int id){ - return types.get(id); - } + @Override + public void despawned(Bullet b){ + Effects.effect(despawneffect, b.x, b.y, b.angle()); + } - public static Array all(){ - return types; - } + @Override + public String getContentTypeName(){ + return "bullettype"; + } + + @Override + public Array getAll(){ + return types; + } } diff --git a/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java index df36debba3..3b034962d8 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java @@ -16,10 +16,10 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class LiquidBulletType extends BulletType { +public class LiquidBulletType extends BulletType{ Liquid liquid; - public LiquidBulletType(Liquid liquid) { + public LiquidBulletType(Liquid liquid){ super(2.5f, 0); this.liquid = liquid; @@ -31,14 +31,14 @@ public class LiquidBulletType extends BulletType { } @Override - public void draw(Bullet b) { + public void draw(Bullet b){ Draw.color(liquid.color, Color.WHITE, b.fout() / 100f + Mathf.randomSeedRange(b.id, 0.1f)); - Fill.circle(b.x, b.y, 0.5f + b.fout()*2.5f); + Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f); } @Override - public void hit(Bullet b, float hitx, float hity) { + public void hit(Bullet b, float hitx, float hity){ Effects.effect(hiteffect, liquid.color, hitx, hity); Puddle.deposit(world.tileWorld(hitx, hity), liquid, 5f); @@ -46,7 +46,7 @@ public class LiquidBulletType extends BulletType { float intensity = 400f; Fire.extinguish(world.tileWorld(hitx, hity), intensity); for(GridPoint2 p : Geometry.d4){ - Fire.extinguish(world.tileWorld(hitx + p.x*tilesize, hity + p.y*tilesize), intensity); + Fire.extinguish(world.tileWorld(hitx + p.x * tilesize, hity + p.y * tilesize), intensity); } } } diff --git a/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java index 20747c7fa4..6179d2e6a3 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java @@ -4,9 +4,9 @@ import io.anuke.mindustry.content.fx.BulletFx; import io.anuke.mindustry.graphics.Palette; import io.anuke.ucore.core.Effects; -public class MissileBulletType extends BasicBulletType { +public class MissileBulletType extends BasicBulletType{ - public MissileBulletType(float speed, float damage, String bulletSprite) { + public MissileBulletType(float speed, float damage, String bulletSprite){ super(speed, damage, bulletSprite); backColor = Palette.missileYellowBack; frontColor = Palette.missileYellow; @@ -14,7 +14,7 @@ public class MissileBulletType extends BasicBulletType { } @Override - public void update(Bullet b) { + public void update(Bullet b){ super.update(b); if(b.timer.get(0, 4f)){ diff --git a/core/src/io/anuke/mindustry/entities/effect/Decal.java b/core/src/io/anuke/mindustry/entities/effect/Decal.java index 7f936235d6..35bd82f240 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Decal.java +++ b/core/src/io/anuke/mindustry/entities/effect/Decal.java @@ -10,24 +10,26 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.groundEffectGroup; -/**Class for creating block rubble on the ground.*/ -public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait { +/** + * Class for creating block rubble on the ground. + */ +public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{ private static final Color color = Color.valueOf("52504e"); @Override - public float lifetime() { + public float lifetime(){ return 8200f; } @Override public void draw(){ - Draw.color(color.r, color.g, color.b, 1f-Mathf.curve(fin(), 0.98f)); + Draw.color(color.r, color.g, color.b, 1f - Mathf.curve(fin(), 0.98f)); drawDecal(); Draw.color(); } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return groundEffectGroup; } diff --git a/core/src/io/anuke/mindustry/entities/effect/Fire.java b/core/src/io/anuke/mindustry/entities/effect/Fire.java index 078bb4b1a0..e933e5dfbf 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Fire.java +++ b/core/src/io/anuke/mindustry/entities/effect/Fire.java @@ -31,7 +31,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable { +public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{ private static final IntMap map = new IntMap<>(); private static final float baseLifetime = 1000f; @@ -41,7 +41,15 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable private float baseFlammability = -1, puddleFlammability; private float lifetime; - /**Start a fire on the tile. If there already is a file there, refreshes its lifetime.*/ + /** + * Deserialization use only! + */ + public Fire(){ + } + + /** + * Start a fire on the tile. If there already is a file there, refreshes its lifetime. + */ public static void create(Tile tile){ if(Net.client() || tile == null) return; //not clientside. @@ -60,24 +68,28 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } } - /**Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.*/ - public static void extinguish(Tile tile, float intensity) { - if (tile != null && map.containsKey(tile.packedPosition())) { + /** + * Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing. + */ + public static void extinguish(Tile tile, float intensity){ + if(tile != null && map.containsKey(tile.packedPosition())){ map.get(tile.packedPosition()).time += intensity * Timers.delta(); } } - /**Deserialization use only!*/ - public Fire(){} + @Remote(called = Loc.server, in = In.entities) + public static void onFireRemoved(int fireid){ + fireGroup.removeByID(fireid); + } @Override - public float lifetime() { + public float lifetime(){ return lifetime; } @Override - public void update() { - if(Mathf.chance(0.1 * Timers.delta())) { + public void update(){ + if(Mathf.chance(0.1 * Timers.delta())){ Effects.effect(EnvironmentFx.fire, x + Mathf.range(4f), y + Mathf.range(4f)); } @@ -91,9 +103,10 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable time = Mathf.clamp(time + Timers.delta(), 0, lifetime()); - if(time >= lifetime()){ + if(time >= lifetime() || tile == null){ CallEntity.onFireRemoved(getID()); remove(); + return; } TileEntity entity = tile.target().entity; @@ -102,19 +115,19 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable float flammability = baseFlammability + puddleFlammability; if(!damage && flammability <= 0){ - time += Timers.delta()*8; + time += Timers.delta() * 8; } - if (baseFlammability < 0 || block != tile.block()){ + if(baseFlammability < 0 || block != tile.block()){ baseFlammability = tile.block().getFlammability(tile); block = tile.block(); } - if(damage) { + if(damage){ lifetime += Mathf.clamp(flammability / 8f, 0f, 0.6f) * Timers.delta(); } - if (flammability > 1f && Mathf.chance(0.03 * Timers.delta() * Mathf.clamp(flammability/5f, 0.3f, 2f))) { + if(flammability > 1f && Mathf.chance(0.03 * Timers.delta() * Mathf.clamp(flammability / 5f, 0.3f, 2f))){ GridPoint2 p = Mathf.select(Geometry.d4); Tile other = world.tile(tile.x + p.x, tile.y + p.y); create(other); @@ -127,7 +140,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable if(Mathf.chance(0.1 * Timers.delta())){ Puddle p = Puddle.getPuddle(tile); if(p != null){ - puddleFlammability = p.getFlammability()/3f; + puddleFlammability = p.getFlammability() / 3f; }else{ puddleFlammability = 0; } @@ -140,14 +153,14 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ stream.writeInt(tile.packedPosition()); stream.writeFloat(lifetime); stream.writeFloat(time); } @Override - public void readSave(DataInput stream) throws IOException { + public void readSave(DataInput stream) throws IOException{ this.loadedPosition = stream.readInt(); this.lifetime = stream.readFloat(); this.time = stream.readFloat(); @@ -155,19 +168,19 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } @Override - public void write(DataOutput data) throws IOException { + public void write(DataOutput data) throws IOException{ data.writeFloat(x); data.writeFloat(y); } @Override - public void read(DataInput data, long time) throws IOException { + public void read(DataInput data, long time) throws IOException{ x = data.readFloat(); y = data.readFloat(); } @Override - public void reset() { + public void reset(){ loadedPosition = -1; tile = null; baseFlammability = -1; @@ -175,7 +188,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } @Override - public void added() { + public void added(){ if(loadedPosition != -1){ map.put(loadedPosition, this); tile = world.tile(loadedPosition); @@ -184,7 +197,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } @Override - public void removed() { + public void removed(){ if(tile != null){ map.remove(tile.packedPosition()); } @@ -192,12 +205,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return fireGroup; } - - @Remote(called = Loc.server, in = In.entities) - public static void onFireRemoved(int fireid){ - fireGroup.removeByID(fireid); - } } diff --git a/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java b/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java index 99187ee60a..889c04a7ce 100644 --- a/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java +++ b/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java @@ -9,27 +9,29 @@ import io.anuke.ucore.entities.impl.EffectEntity; import io.anuke.ucore.function.EffectRenderer; import io.anuke.ucore.util.Mathf; -/**A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.*/ -public class GroundEffectEntity extends EffectEntity { +/** + * A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer. + */ +public class GroundEffectEntity extends EffectEntity{ private boolean once; @Override public void update(){ - GroundEffect effect = (GroundEffect)this.effect; + GroundEffect effect = (GroundEffect) this.effect; - if(effect.isStatic) { + if(effect.isStatic){ time += Timers.delta(); time = Mathf.clamp(time, 0, effect.staticLife); - if (!once && time >= lifetime()) { + if(!once && time >= lifetime()){ once = true; time = 0f; Tile tile = Vars.world.tileWorld(x, y); if(tile != null && tile.floor().isLiquid){ remove(); } - } else if (once && time >= effect.staticLife) { + }else if(once && time >= effect.staticLife){ remove(); } }else{ @@ -39,7 +41,7 @@ public class GroundEffectEntity extends EffectEntity { @Override public void draw(){ - GroundEffect effect = (GroundEffect)this.effect; + GroundEffect effect = (GroundEffect) this.effect; if(once && effect.isStatic) Effects.renderEffect(id, effect, color, lifetime(), rotation, x, y, data); @@ -48,32 +50,38 @@ public class GroundEffectEntity extends EffectEntity { } @Override - public void reset() { + public void reset(){ super.reset(); once = false; } - /**An effect that is rendered on the ground layer as opposed to the top layer.*/ + /** + * An effect that is rendered on the ground layer as opposed to the top layer. + */ public static class GroundEffect extends Effect{ - /**How long this effect stays on the ground when static.*/ + /** + * How long this effect stays on the ground when static. + */ public final float staticLife; - /**If true, this effect will stop and lie on the ground for a specific duration, - * after its initial lifetime is over.*/ + /** + * If true, this effect will stop and lie on the ground for a specific duration, + * after its initial lifetime is over. + */ public final boolean isStatic; - public GroundEffect(float life, float staticLife, EffectRenderer draw) { + public GroundEffect(float life, float staticLife, EffectRenderer draw){ super(life, draw); this.staticLife = staticLife; this.isStatic = true; } - public GroundEffect(boolean isStatic, float life, EffectRenderer draw) { + public GroundEffect(boolean isStatic, float life, EffectRenderer draw){ super(life, draw); this.staticLife = 0f; this.isStatic = isStatic; } - public GroundEffect(float life, EffectRenderer draw) { + public GroundEffect(float life, EffectRenderer draw){ super(life, draw); this.staticLife = 0f; this.isStatic = false; diff --git a/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java b/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java index 2e4063ef8b..284b66420d 100644 --- a/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java +++ b/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java @@ -35,7 +35,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawTrait, VelocityTrait, TimeTrait, TargetTrait, Poolable { +public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawTrait, VelocityTrait, TimeTrait, TargetTrait, Poolable{ private static final float sinkLifetime = 80f; private Interpolator interpolator = new Interpolator(); @@ -46,6 +46,14 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT private float time; private float sinktime; + /** + * Internal use only! + */ + public ItemDrop(){ + hitbox.setSize(5f); + hitboxTile.setSize(5f); + } + public static ItemDrop create(Item item, int amount, float x, float y, float angle){ ItemDrop drop = new ItemDrop(); drop.item = item; @@ -73,13 +81,7 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT } } - /**Internal use only!*/ - public ItemDrop(){ - hitbox.setSize(5f); - hitboxTile.setSize(5f); - } - - public Item getItem() { + public Item getItem(){ return item; } @@ -88,66 +90,66 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT } @Override - public boolean isDead() { + public boolean isDead(){ return !isAdded(); } @Override - public Team getTeam() { + public Team getTeam(){ return Team.none; } @Override - public float lifetime() { - return 60*60; + public float lifetime(){ + return 60 * 60; } @Override - public void time(float time) { + public void time(float time){ this.time = time; } @Override - public float time() { + public float time(){ return time; } @Override - public Vector2 getVelocity() { + public Vector2 getVelocity(){ return velocity; } @Override - public boolean collides(SolidTrait other) { + public boolean collides(SolidTrait other){ return other instanceof Player && time > 20f; } @Override - public void collision(SolidTrait other, float x, float y) { - Unit player = (Unit)other; + public void collision(SolidTrait other, float x, float y){ + Unit player = (Unit) other; if(player.inventory.canAcceptItem(item, 1)){ int used = Math.min(amount, player.inventory.capacity() - player.inventory.getItem().amount); player.inventory.addItem(item, used); amount -= used; - if(amount <= 0) { + if(amount <= 0){ CallEntity.onPickup(getID()); } } } @Override - public void draw() { - float size = itemSize * (1f - sinktime/sinkLifetime) * (1f-Mathf.curve(fin(), 0.98f)); + public void draw(){ + float size = itemSize * (1f - sinktime / sinkLifetime) * (1f - Mathf.curve(fin(), 0.98f)); Tile tile = world.tileWorld(x, y); - Draw.color(Color.WHITE, tile == null || !tile.floor().isLiquid ? Color.WHITE : tile.floor().liquidColor, sinktime/sinkLifetime); + Draw.color(Color.WHITE, tile == null || !tile.floor().isLiquid ? Color.WHITE : tile.floor().liquidColor, sinktime / sinkLifetime); Draw.rect(item.region, x, y, size, size); int stored = Mathf.clamp(amount / 6, 1, 8); - for(int i = 0; i < stored; i ++) { + for(int i = 0; i < stored; i++){ float px = stored == 1 ? 0 : Mathf.randomSeedRange(i + 1, 4f); float py = stored == 1 ? 0 : Mathf.randomSeedRange(i + 2, 4f); Draw.rect(item.region, x + px, y + py, size, size); @@ -157,8 +159,8 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT } @Override - public void update() { - if(Net.client()) { + public void update(){ + if(Net.client()){ interpolate(); }else{ updateVelocity(0.2f); @@ -190,28 +192,28 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT } @Override - public void reset() { + public void reset(){ time = 0f; interpolator.reset(); } @Override - public Interpolator getInterpolator() { + public Interpolator getInterpolator(){ return interpolator; } @Override - public float drawSize() { + public float drawSize(){ return 10; } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return itemGroup; } @Override - public void writeSave(DataOutput data) throws IOException { + public void writeSave(DataOutput data) throws IOException{ data.writeFloat(x); data.writeFloat(y); data.writeByte(item.id); @@ -219,7 +221,7 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT } @Override - public void readSave(DataInput data) throws IOException { + public void readSave(DataInput data) throws IOException{ x = data.readFloat(); y = data.readFloat(); item = Item.getByID(data.readByte()); diff --git a/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java b/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java index 2eba1b7511..5351f5af64 100644 --- a/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java +++ b/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java @@ -32,17 +32,22 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ private PosTrait to; private Runnable done; + public ItemTransfer(){ + } + @Remote(in = In.entities, called = Loc.server, unreliable = true) public static void transferAmmo(Item item, float x, float y, Unit to){ if(to == null) return; to.addAmmo(item); - create(item, x, y, to, () -> {}); + create(item, x, y, to, () -> { + }); } @Remote(in = In.entities, called = Loc.server, unreliable = true) public static void transferItemEffect(Item item, float x, float y, Unit to){ if(to == null) return; - create(item, x, y, to, () -> {}); + create(item, x, y, to, () -> { + }); } @Remote(in = In.entities, called = Loc.server, unreliable = true) @@ -54,10 +59,11 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ @Remote(in = In.entities, called = Loc.server) public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){ if(tile == null) return; - for (int i = 0; i < Mathf.clamp(amount/3, 1, 8); i++) { - Timers.run(i*3, () -> create(item, x, y, tile, () -> {})); + for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ + Timers.run(i * 3, () -> create(item, x, y, tile, () -> { + })); } - tile.entity.items.addItem(item, amount); + tile.entity.items.add(item, amount); } public static void create(Item item, float fromx, float fromy, PosTrait to, Runnable done){ @@ -70,15 +76,13 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ tr.add(); } - public ItemTransfer(){} - @Override - public float lifetime() { + public float lifetime(){ return 60; } @Override - public void reset() { + public void reset(){ super.reset(); item = null; to = null; @@ -89,7 +93,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ } @Override - public void removed() { + public void removed(){ if(done != null){ threads.run(done); } @@ -97,7 +101,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ } @Override - public void update() { + public void update(){ if(to == null){ remove(); return; @@ -110,24 +114,24 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{ } @Override - public void draw() { - float length = fslope()*6f; + public void draw(){ + float length = fslope() * 6f; float angle = current.set(x, y).sub(from).angle(); Draw.color(Palette.accent); - Lines.stroke(fslope()*2f); + Lines.stroke(fslope() * 2f); - Lines.circle(x, y, fslope()*2f); + Lines.circle(x, y, fslope() * 2f); Lines.lineAngleCenter(x, y, angle, length); - Lines.lineAngle(x, y, angle, fout()*6f); + Lines.lineAngle(x, y, angle, fout() * 6f); Draw.color(item.color); - Fill.circle(x, y, fslope()*1.5f); + Fill.circle(x, y, fslope() * 1.5f); Draw.reset(); } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return effectGroup; } diff --git a/core/src/io/anuke/mindustry/entities/effect/Lightning.java b/core/src/io/anuke/mindustry/entities/effect/Lightning.java index 37cd52523c..2ab599b003 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Lightning.java +++ b/core/src/io/anuke/mindustry/entities/effect/Lightning.java @@ -46,7 +46,15 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT private Color color = Palette.lancerLaser; private SeedRandom random = new SeedRandom(); - /**Create a lighting branch at a location. Use Team.none to damage everyone.*/ + /** + * For pooling use only. Do not call directly! + */ + public Lightning(){ + } + + /** + * Create a lighting branch at a location. Use Team.none to damage everyone. + */ public static void create(Team team, Effect effect, Color color, float damage, float x, float y, float targetAngle, int length){ CallEntity.createLighting(lastSeed++, team, effect, color, damage, x, y, targetAngle, length); } @@ -69,7 +77,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT Units.getNearbyEnemies(team, rect, entities::add); - for(int i = 0; i < length; i ++){ + for(int i = 0; i < length; i++){ l.lines.add(new Vector2(x, y)); float fx = x, fy = y; @@ -82,15 +90,15 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT Units.getNearbyEnemies(team, rect, entity -> { float dst = entity.distanceTo(x2, y2); - if(dst < attractRange) { + if(dst < attractRange){ angle = Mathf.slerp(angle, Angles.angle(x2, y2, entity.x, entity.y), (attractRange - dst) / attractRange / 4f); } entity.getHitbox(hitrect); - hitrect.x -= range/2f; - hitrect.y -= range/2f; - hitrect.width += range/2f; - hitrect.height += range/2f; + hitrect.x -= range / 2f; + hitrect.y -= range / 2f; + hitrect.width += range / 2f; + hitrect.height += range / 2f; if(hitrect.contains(x2, y2) || hitrect.contains(fx, fy)){ float result = damage; @@ -104,7 +112,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT }); if(l.random.chance(0.1f)){ - createLighting(l.random.nextInt(), team, effect, color, damage, x2, y2, angle + l.random.range(100f), length/3); + createLighting(l.random.nextInt(), team, effect, color, damage, x2, y2, angle + l.random.range(100f), length / 3); } x = x2; @@ -115,47 +123,44 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT l.add(); } - /**For pooling use only. Do not call directly!*/ - public Lightning(){} - @Override - public boolean isSyncing() { + public boolean isSyncing(){ return false; } @Override - public void write(DataOutput data) throws IOException { + public void write(DataOutput data) throws IOException{ } @Override - public void read(DataInput data, long time) throws IOException { + public void read(DataInput data, long time) throws IOException{ } @Override - public float lifetime() { + public float lifetime(){ return 10; } @Override - public void reset() { + public void reset(){ color = Palette.lancerLaser; lines.clear(); } @Override - public void removed() { + public void removed(){ Pooling.free(this); } @Override - public void draw() { + public void draw(){ float lx = x, ly = y; Draw.color(color, Color.WHITE, fin()); - for(int i = 0; i < lines.size; i ++){ + for(int i = 0; i < lines.size; i++){ Vector2 v = lines.get(i); - Lines.stroke(fout() * 3f + 1f-(float)i/lines.size); + Lines.stroke(fout() * 3f + 1f - (float) i / lines.size); Lines.line(lx, ly, v.x, v.y); lx = v.x; ly = v.y; @@ -164,7 +169,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return bulletGroup; } } diff --git a/core/src/io/anuke/mindustry/entities/effect/Puddle.java b/core/src/io/anuke/mindustry/entities/effect/Puddle.java index 0aa7032348..1fa0cd8a0b 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Puddle.java +++ b/core/src/io/anuke/mindustry/entities/effect/Puddle.java @@ -40,7 +40,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.puddleGroup; import static io.anuke.mindustry.Vars.world; -public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait { +public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait{ private static final IntMap map = new IntMap<>(); private static final float maxLiquid = 70f; private static final int maxGeneration = 2; @@ -58,17 +58,29 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait private float accepting; private byte generation; - /**Deposists a puddle between tile and source.*/ + /** + * Deserialization use only! + */ + public Puddle(){ + } + + /** + * Deposists a puddle between tile and source. + */ public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){ deposit(tile, source, liquid, amount, 0); } - /**Deposists a puddle at a tile.*/ + /** + * Deposists a puddle at a tile. + */ public static void deposit(Tile tile, Liquid liquid, float amount){ deposit(tile, tile, liquid, amount, 0); } - /**Returns the puddle on the specified tile. May return null.*/ + /** + * Returns the puddle on the specified tile. May return null. + */ public static Puddle getPuddle(Tile tile){ return map.get(tile.packedPosition()); } @@ -76,11 +88,11 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){ if(tile.floor().isLiquid && !canStayOn(liquid, tile.floor().liquidDrop)){ reactPuddle(tile.floor().liquidDrop, liquid, amount, tile, - (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); if(generation == 0 && Timers.get(tile, "ripple", 50)){ Effects.effect(BlockFx.ripple, tile.floor().liquidDrop.color, - (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); } return; } @@ -93,28 +105,32 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait puddle.tile = tile; puddle.liquid = liquid; puddle.amount = amount; - puddle.generation = (byte)generation; - puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + puddle.generation = (byte) generation; + puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); puddle.add(); map.put(tile.packedPosition(), puddle); }else if(p.liquid == liquid){ p.accepting = Math.max(amount, p.accepting); - if(generation == 0 && Timers.get(p, "ripple2", 50) && p.amount >= maxLiquid/2f){ - Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + if(generation == 0 && Timers.get(p, "ripple2", 50) && p.amount >= maxLiquid / 2f){ + Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); } }else{ p.amount -= reactPuddle(p.liquid, liquid, amount, p.tile, p.x, p.y); } } - /**Returns whether the first liquid can 'stay' on the second one. - * Currently, the only place where this can happen is oil on water.*/ + /** + * Returns whether the first liquid can 'stay' on the second one. + * Currently, the only place where this can happen is oil on water. + */ private static boolean canStayOn(Liquid liquid, Liquid other){ return liquid == Liquids.oil && other == Liquids.water; } - /**Reacts two liquids together at a location.*/ + /** + * Reacts two liquids together at a location. + */ private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){ if((dest.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid @@ -126,25 +142,27 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait if(Mathf.chance(0.5f * amount)){ Effects.effect(EnvironmentFx.steam, x, y); } - return - 0.1f * amount; + return -0.1f * amount; }else if(liquid.temperature > 0.7f && dest.temperature < 0.55f){ //hot liquid poured onto cold puddle if(Mathf.chance(0.8f * amount)){ Effects.effect(EnvironmentFx.steam, x, y); } - return - 0.4f * amount; + return -0.4f * amount; } return 0f; } - /**Deserialization use only!*/ - public Puddle(){} + @Remote(called = Loc.server, in = In.entities) + public static void onPuddleRemoved(int puddleid){ + puddleGroup.removeByID(puddleid); + } public float getFlammability(){ return liquid.flammability * amount; } @Override - public void update() { + public void update(){ //no updating happens clientside if(Net.client()){ @@ -158,11 +176,11 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait amount += accepting; accepting = 0f; - if (amount >= maxLiquid / 1.5f && generation < maxGeneration) { + if(amount >= maxLiquid / 1.5f && generation < maxGeneration){ float deposited = Math.min((amount - maxLiquid / 1.5f) / 4f, 0.3f) * Timers.delta(); - for (GridPoint2 point : Geometry.d4) { + for(GridPoint2 point : Geometry.d4){ Tile other = world.tile(tile.x + point.x, tile.y + point.y); - if (other.block() == Blocks.air && other.cliffs == 0) { + if(other.block() == Blocks.air && other.cliffs == 0){ deposit(other, tile, liquid, deposited, generation + 1); amount -= deposited / 2f; //tweak to speed up/slow down puddle propagation } @@ -171,14 +189,14 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait amount = Mathf.clamp(amount, 0, maxLiquid); - if (amount <= 0f) { + if(amount <= 0f){ CallEntity.onPuddleRemoved(getID()); } } //effects-only code - if(amount >= maxLiquid/2f && updateTime <= 0f){ - Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(x, y), unit -> { + if(amount >= maxLiquid / 2f && updateTime <= 0f){ + Units.getNearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> { if(unit.isFlying()) return; unit.getHitbox(rect2); @@ -186,7 +204,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait unit.applyEffect(liquid.effect, 0.5f); - if(unit.getVelocity().len() > 0.1) { + if(unit.getVelocity().len() > 0.1){ Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y); } }); @@ -202,30 +220,30 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait } @Override - public void draw() { + public void draw(){ seeds = id; boolean onLiquid = tile.floor().isLiquid; - float f = Mathf.clamp(amount/(maxLiquid/1.5f)); + float f = Mathf.clamp(amount / (maxLiquid / 1.5f)); float smag = onLiquid ? 0.8f : 0f; float sscl = 20f; Draw.color(Hue.shift(tmp.set(liquid.color), 2, -0.05f)); - Fill.circle(x + Mathf.sin(Timers.time() + seeds*532, sscl, smag), y + Mathf.sin(Timers.time() + seeds*53, sscl, smag), f * 8f); + Fill.circle(x + Mathf.sin(Timers.time() + seeds * 532, sscl, smag), y + Mathf.sin(Timers.time() + seeds * 53, sscl, smag), f * 8f); Angles.randLenVectors(id, 3, f * 6f, (ex, ey) -> { - Fill.circle(x + ex + Mathf.sin(Timers.time() + seeds*532, sscl, smag), - y + ey + Mathf.sin(Timers.time() + seeds*53, sscl, smag), f * 5f); - seeds ++; + Fill.circle(x + ex + Mathf.sin(Timers.time() + seeds * 532, sscl, smag), + y + ey + Mathf.sin(Timers.time() + seeds * 53, sscl, smag), f * 5f); + seeds++; }); Draw.color(); } @Override - public float drawSize() { + public float drawSize(){ return 20; } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ stream.writeInt(tile.packedPosition()); stream.writeFloat(x); stream.writeFloat(y); @@ -235,7 +253,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait } @Override - public void readSave(DataInput stream) throws IOException { + public void readSave(DataInput stream) throws IOException{ this.loadedPosition = stream.readInt(); this.x = stream.readFloat(); this.y = stream.readFloat(); @@ -246,7 +264,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait } @Override - public void reset() { + public void reset(){ loadedPosition = -1; tile = null; liquid = null; @@ -256,7 +274,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait } @Override - public void added() { + public void added(){ if(loadedPosition != -1){ map.put(loadedPosition, this); tile = world.tile(loadedPosition); @@ -264,38 +282,33 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait } @Override - public void removed() { + public void removed(){ map.remove(tile.packedPosition()); reset(); } @Override - public void write(DataOutput data) throws IOException { + public void write(DataOutput data) throws IOException{ data.writeFloat(x); data.writeFloat(y); data.writeByte(liquid.id); - data.writeShort((short)(amount * 4)); + data.writeShort((short) (amount * 4)); data.writeInt(tile.packedPosition()); } @Override - public void read(DataInput data, long time) throws IOException { + public void read(DataInput data, long time) throws IOException{ x = data.readFloat(); y = data.readFloat(); liquid = Liquid.getByID(data.readByte()); - targetAmount = data.readShort()/4f; + targetAmount = data.readShort() / 4f; tile = world.tile(data.readInt()); map.put(tile.packedPosition(), this); } @Override - public EntityGroup targetGroup() { + public EntityGroup targetGroup(){ return puddleGroup; } - - @Remote(called = Loc.server, in = In.entities) - public static void onPuddleRemoved(int puddleid){ - puddleGroup.removeByID(puddleid); - } } diff --git a/core/src/io/anuke/mindustry/entities/effect/RubbleDecal.java b/core/src/io/anuke/mindustry/entities/effect/RubbleDecal.java index 217dc9e62a..8fb5dedf98 100644 --- a/core/src/io/anuke/mindustry/entities/effect/RubbleDecal.java +++ b/core/src/io/anuke/mindustry/entities/effect/RubbleDecal.java @@ -3,10 +3,12 @@ package io.anuke.mindustry.entities.effect; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public class RubbleDecal extends Decal { +public class RubbleDecal extends Decal{ private int size; - /**Creates a rubble effect at a position. Provide a block size to use.*/ + /** + * Creates a rubble effect at a position. Provide a block size to use. + */ public static void create(float x, float y, int size){ RubbleDecal decal = new RubbleDecal(); decal.size = size; diff --git a/core/src/io/anuke/mindustry/entities/effect/ScorchDecal.java b/core/src/io/anuke/mindustry/entities/effect/ScorchDecal.java index 1ef31e49fc..7bfc3e369e 100644 --- a/core/src/io/anuke/mindustry/entities/effect/ScorchDecal.java +++ b/core/src/io/anuke/mindustry/entities/effect/ScorchDecal.java @@ -8,21 +8,21 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class ScorchDecal extends Decal { +public class ScorchDecal extends Decal{ private static final int scorches = 5; private static final TextureRegion[] regions = new TextureRegion[scorches]; public static void create(float x, float y){ if(regions[0] == null){ - for (int i = 0; i < regions.length; i++) { - regions[i] = Draw.region("scorch" + (i+1)); + for(int i = 0; i < regions.length; i++){ + regions[i] = Draw.region("scorch" + (i + 1)); } } Tile tile = world.tileWorld(x, y); if(tile == null || tile.floor().liquidDrop != null) return; - + ScorchDecal decal = new ScorchDecal(); decal.set(x, y); decal.add(); @@ -31,10 +31,10 @@ public class ScorchDecal extends Decal { @Override public void drawDecal(){ - for (int i = 0; i < 5; i++) { - TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches-1)]; + for(int i = 0; i < 5; i++){ + TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches - 1)]; float rotation = Mathf.randomSeed(id + i, 0, 360); - float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20)/10f; + float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20) / 10f; Draw.grect(region, x + Angles.trnsx(rotation, space), y + Angles.trnsy(rotation, space), rotation - 90); } } diff --git a/core/src/io/anuke/mindustry/entities/effect/Shield.java b/core/src/io/anuke/mindustry/entities/effect/Shield.java index 31f7175048..da10da3fde 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Shield.java +++ b/core/src/io/anuke/mindustry/entities/effect/Shield.java @@ -13,44 +13,43 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.shieldGroup; //todo re-implement -public class Shield extends BaseEntity implements DrawTrait { - public boolean active; - public boolean hitPlayers = false; - public float radius = 0f; - - private float uptime = 0f; - private final Tile tile; - - public Shield(Tile tile){ - this.tile = tile; - this.x = tile.worldx(); - this.y = tile.worldy(); - } - - public float drawSize(){ - return 150; - } - - @Override - public void update(){ - float alpha = 0.1f; - Interpolation interp = Interpolation.fade; - - if(active){ - uptime = interp.apply(uptime, 1f, alpha * Timers.delta()); - }else{ - uptime = interp.apply(uptime, 0f, alpha * Timers.delta()); - if(uptime <= 0.05f) - remove(); - } - uptime = Mathf.clamp(uptime); - - if(!(tile.block() instanceof ShieldBlock)){ - remove(); - return; - } - - ShieldBlock block = (ShieldBlock)tile.block(); +public class Shield extends BaseEntity implements DrawTrait{ + private final Tile tile; + public boolean active; + public boolean hitPlayers = false; + public float radius = 0f; + private float uptime = 0f; + + public Shield(Tile tile){ + this.tile = tile; + this.x = tile.worldx(); + this.y = tile.worldy(); + } + + public float drawSize(){ + return 150; + } + + @Override + public void update(){ + float alpha = 0.1f; + Interpolation interp = Interpolation.fade; + + if(active){ + uptime = interp.apply(uptime, 1f, alpha * Timers.delta()); + }else{ + uptime = interp.apply(uptime, 0f, alpha * Timers.delta()); + if(uptime <= 0.05f) + remove(); + } + uptime = Mathf.clamp(uptime); + + if(!(tile.block() instanceof ShieldBlock)){ + remove(); + return; + } + + ShieldBlock block = (ShieldBlock) tile.block(); /* Entities.getNearby(bulletGroup, x, y, block.shieldRadius * 2*uptime + 10, entity->{ @@ -64,39 +63,39 @@ public class Shield extends BaseEntity implements DrawTrait { } } });*/ - } - - @Override - public void draw(){ - if(!(tile.block() instanceof ShieldBlock) || radius <= 1f){ - return; - } + } - Fill.circle(x, y, drawRadius()); - } - - float drawRadius(){ - return (radius + Mathf.sin(Timers.time(), 25f, 1f)); - } - - public void removeDelay(){ - active = false; - } + @Override + public void draw(){ + if(!(tile.block() instanceof ShieldBlock) || radius <= 1f){ + return; + } - @Override - public EntityGroup targetGroup() { - return shieldGroup; - } + Fill.circle(x, y, drawRadius()); + } + + float drawRadius(){ + return (radius + Mathf.sin(Timers.time(), 25f, 1f)); + } + + public void removeDelay(){ + active = false; + } + + @Override + public EntityGroup targetGroup(){ + return shieldGroup; + } + + @Override + public void added(){ + active = true; + } + + @Override + public void removed(){ + active = false; + uptime = 0f; + } - @Override - public void added(){ - active = true; - } - - @Override - public void removed(){ - active = false; - uptime = 0f; - } - } diff --git a/core/src/io/anuke/mindustry/entities/traits/BelowLiquidTrait.java b/core/src/io/anuke/mindustry/entities/traits/BelowLiquidTrait.java index 37ee664fcb..c4abd8abf0 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BelowLiquidTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BelowLiquidTrait.java @@ -1,5 +1,7 @@ package io.anuke.mindustry.entities.traits; -/**A flag interface for marking an effect as appearing below liquids.*/ -public interface BelowLiquidTrait { +/** + * A flag interface for marking an effect as appearing below liquids. + */ +public interface BelowLiquidTrait{ } diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 966cdf8071..bbf7df9f9d 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -37,27 +37,46 @@ import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.tmptr; import static io.anuke.mindustry.Vars.world; -/**Interface for units that build, break or mine things.*/ +/** + * Interface for units that build, break or mine things. + */ public interface BuilderTrait extends Entity{ //these are not instance variables! float placeDistance = 140f; float mineDistance = 70f; - /**Returns the queue for storing build requests.*/ + /** + * Returns the queue for storing build requests. + */ Queue getPlaceQueue(); - /**Returns the tile this builder is currently mining.*/ + /** + * Returns the tile this builder is currently mining. + */ Tile getMineTile(); - /**Sets the tile this builder is currently mining.*/ + /** + * Sets the tile this builder is currently mining. + */ void setMineTile(Tile tile); - /**Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc.*/ + /** + * Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc. + */ float getMinePower(); - /**Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.*/ + /** + * Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all. + */ float getBuildPower(Tile tile); + /** + * Whether this type of builder can begin creating new blocks. + */ + default boolean canCreateBlocks(){ + return true; + } + default void writeBuilding(DataOutput output) throws IOException{ BuildRequest request = getCurrentRequest(); @@ -78,17 +97,17 @@ public interface BuilderTrait extends Entity{ } default void readBuilding(DataInput input, boolean applyChanges) throws IOException{ - synchronized (getPlaceQueue()) { + synchronized(getPlaceQueue()){ if(applyChanges) getPlaceQueue().clear(); byte type = input.readByte(); - if (type != -1) { + if(type != -1){ int position = input.readInt(); BuildRequest request; - if (type == 1) { //remove + if(type == 1){ //remove request = new BuildRequest(position % world.width(), position / world.width()); - } else { //place + }else{ //place byte recipe = input.readByte(); byte rotation = input.readByte(); request = new BuildRequest(position % world.width(), position / world.width(), rotation, Recipe.getByID(recipe)); @@ -101,17 +120,21 @@ public interface BuilderTrait extends Entity{ } } - /**Return whether this builder's place queue contains items.*/ + /** + * Return whether this builder's place queue contains items. + */ default boolean isBuilding(){ return getPlaceQueue().size != 0; } - /**If a place request matching this signature is present, it is removed. - * Otherwise, a new place request is added to the queue.*/ + /** + * If a place request matching this signature is present, it is removed. + * Otherwise, a new place request is added to the queue. + */ default void replaceBuilding(int x, int y, int rotation, Recipe recipe){ - synchronized (getPlaceQueue()) { - for (BuildRequest request : getPlaceQueue()) { - if (request.x == x && request.y == y) { + synchronized(getPlaceQueue()){ + for(BuildRequest request : getPlaceQueue()){ + if(request.x == x && request.y == y){ clearBuilding(); addBuildRequest(request); return; @@ -122,16 +145,20 @@ public interface BuilderTrait extends Entity{ addBuildRequest(new BuildRequest(x, y, rotation, recipe)); } - /**Clears the placement queue.*/ + /** + * Clears the placement queue. + */ default void clearBuilding(){ getPlaceQueue().clear(); } - /**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/ + /** + * Add another build requests to the tail of the queue, if it doesn't exist there yet. + */ default void addBuildRequest(BuildRequest place){ - synchronized (getPlaceQueue()) { - for (BuildRequest request : getPlaceQueue()) { - if (request.x == place.x && request.y == place.y) { + synchronized(getPlaceQueue()){ + for(BuildRequest request : getPlaceQueue()){ + if(request.x == place.x && request.y == place.y){ return; } } @@ -139,16 +166,20 @@ public interface BuilderTrait extends Entity{ } } - /**Return the build requests currently active, or the one at the top of the queue. - * May return null.*/ + /** + * Return the build requests currently active, or the one at the top of the queue. + * May return null. + */ default BuildRequest getCurrentRequest(){ - synchronized (getPlaceQueue()) { + synchronized(getPlaceQueue()){ return getPlaceQueue().size == 0 ? null : getPlaceQueue().first(); } } - /**Update building mechanism for this unit. - * This includes mining.*/ + /** + * Update building mechanism for this unit. + * This includes mining. + */ default void updateBuilding(Unit unit){ BuildRequest current = getCurrentRequest(); @@ -171,10 +202,10 @@ public interface BuilderTrait extends Entity{ Tile tile = world.tile(current.x, current.y); - if (!(tile.block() instanceof BuildBlock)) { - if(!current.remove && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)) { + if(!(tile.block() instanceof BuildBlock)){ + if(canCreateBlocks() && !current.remove && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){ Build.beginPlace(unit.getTeam(), current.x, current.y, current.recipe, current.rotation); - }else if(current.remove && Build.validBreak(unit.getTeam(), current.x, current.y)){ + }else if(canCreateBlocks() && current.remove && Build.validBreak(unit.getTeam(), current.x, current.y)){ Build.beginBreak(unit.getTeam(), current.x, current.y); }else{ getPlaceQueue().removeFirst(); @@ -198,7 +229,9 @@ public interface BuilderTrait extends Entity{ current.progress = entity.progress(); } - /**Do not call directly.*/ + /** + * Do not call directly. + */ default void updateMining(Unit unit){ Tile tile = getMineTile(); @@ -211,26 +244,28 @@ public interface BuilderTrait extends Entity{ if(unit.inventory.canAcceptItem(item) && Mathf.chance(Timers.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){ CallEntity.transferItemToUnit(item, - tile.worldx() + Mathf.range(tilesize/2f), - tile.worldy() + Mathf.range(tilesize/2f), + tile.worldx() + Mathf.range(tilesize / 2f), + tile.worldy() + Mathf.range(tilesize / 2f), unit); } if(Mathf.chance(0.06 * Timers.delta())){ Effects.effect(BlockFx.pulverizeSmall, - tile.worldx() + Mathf.range(tilesize/2f), - tile.worldy() + Mathf.range(tilesize/2f), 0f, item.color); + tile.worldx() + Mathf.range(tilesize / 2f), + tile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color); } } } - /**Draw placement effects for an entity. This includes mining*/ + /** + * Draw placement effects for an entity. This includes mining + */ default void drawBuilding(Unit unit){ BuildRequest request; - synchronized (getPlaceQueue()) { - if (!isBuilding()) { - if (getMineTile() != null) { + synchronized(getPlaceQueue()){ + if(!isBuilding()){ + if(getMineTile() != null){ drawMining(unit); } return; @@ -250,7 +285,7 @@ public interface BuilderTrait extends Entity{ float px = unit.x + Angles.trnsx(unit.rotation, focusLen); float py = unit.y + Angles.trnsy(unit.rotation, focusLen); - float sz = Vars.tilesize*tile.block().size/2f; + float sz = Vars.tilesize * tile.block().size / 2f; float ang = unit.angleTo(tile); tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz); @@ -281,14 +316,16 @@ public interface BuilderTrait extends Entity{ Draw.color(); } - /**Internal use only.*/ + /** + * Internal use only. + */ default void drawMining(Unit unit){ Tile tile = getMineTile(); if(tile == null) return; float focusLen = 4f + Mathf.absin(Timers.time(), 1.1f, 0.5f); - float swingScl = 12f, swingMag = tilesize/8f; + float swingScl = 12f, swingMag = tilesize / 8f; float flashScl = 0.3f; float px = unit.x + Angles.trnsx(unit.rotation, focusLen); @@ -297,10 +334,10 @@ public interface BuilderTrait extends Entity{ float ex = tile.worldx() + Mathf.sin(Timers.time() + 48, swingScl, swingMag); float ey = tile.worldy() + Mathf.sin(Timers.time() + 48, swingScl + 2f, swingMag); - Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f-flashScl + Mathf.absin(Timers.time(), 0.5f, flashScl)); + Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f - flashScl + Mathf.absin(Timers.time(), 0.5f, flashScl)); Shapes.laser("minelaser", "minelaser-end", px, py, ex, ey); - if(unit instanceof Player && ((Player) unit).isLocal) { + if(unit instanceof Player && ((Player) unit).isLocal){ Draw.color(Palette.accent); Lines.poly(tile.worldx(), tile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Timers.time()); } @@ -308,16 +345,20 @@ public interface BuilderTrait extends Entity{ Draw.color(); } - /**Class for storing build requests. Can be either a place or remove request.*/ - class BuildRequest { + /** + * Class for storing build requests. Can be either a place or remove request. + */ + class BuildRequest{ public final int x, y, rotation; public final Recipe recipe; public final boolean remove; public float progress; - /**This creates a build request.*/ - public BuildRequest(int x, int y, int rotation, Recipe recipe) { + /** + * This creates a build request. + */ + public BuildRequest(int x, int y, int rotation, Recipe recipe){ this.x = x; this.y = y; this.rotation = rotation; @@ -325,8 +366,10 @@ public interface BuilderTrait extends Entity{ this.remove = false; } - /**This creates a remove request.*/ - public BuildRequest(int x, int y) { + /** + * This creates a remove request. + */ + public BuildRequest(int x, int y){ this.x = x; this.y = y; this.rotation = -1; diff --git a/core/src/io/anuke/mindustry/entities/traits/CarriableTrait.java b/core/src/io/anuke/mindustry/entities/traits/CarriableTrait.java index c21bd5ccf5..296b782154 100644 --- a/core/src/io/anuke/mindustry/entities/traits/CarriableTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/CarriableTrait.java @@ -8,6 +8,7 @@ public interface CarriableTrait extends TeamTrait, TargetTrait, SolidTrait{ return getCarrier() != null; } - void setCarrier(CarryTrait carrier); CarryTrait getCarrier(); + + void setCarrier(CarryTrait carrier); } diff --git a/core/src/io/anuke/mindustry/entities/traits/CarryTrait.java b/core/src/io/anuke/mindustry/entities/traits/CarryTrait.java index 7a3e161ff9..63c10a4578 100644 --- a/core/src/io/anuke/mindustry/entities/traits/CarryTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/CarryTrait.java @@ -10,28 +10,6 @@ import io.anuke.ucore.core.Effects; import io.anuke.ucore.entities.trait.SolidTrait; public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{ - /**Returns the thing this carrier is carrying.*/ - CarriableTrait getCarry(); - /**Sets the carrying unit. Internal use only! Use {@link #carry(CarriableTrait)} to set state.*/ - void setCarry(CarriableTrait unit); - /**Returns maximum mass this carrier can carry.*/ - float getCarryWeight(); - - /**Drops the unit that is being carried, if applicable.*/ - default void dropCarry(){ - carry(null); - } - - default void dropCarryLocal(){ - setCarryOf(null, this, null); - } - - /**Do not override unless absolutely necessary. - * Carries a unit. To drop a unit, call with {@code null}.*/ - default void carry(CarriableTrait unit){ - CallEntity.setCarryOf(this instanceof Player ? (Player)this : null, this, unit); - } - @Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities) static void dropSelf(Player player){ if(player.getCarrier() != null){ @@ -41,6 +19,7 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{ @Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities) static void setCarryOf(Player player, CarryTrait trait, CarriableTrait unit){ + if(trait == null) return; if(player != null){ //when a server recieves this called from a player, set the carrier to the player. trait = player; } @@ -61,4 +40,38 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{ Effects.effect(UnitFx.unitPickup, trait); } } + + /** + * Returns the thing this carrier is carrying. + */ + CarriableTrait getCarry(); + + /** + * Sets the carrying unit. Internal use only! Use {@link #carry(CarriableTrait)} to set state. + */ + void setCarry(CarriableTrait unit); + + /** + * Returns maximum mass this carrier can carry. + */ + float getCarryWeight(); + + /** + * Drops the unit that is being carried, if applicable. + */ + default void dropCarry(){ + carry(null); + } + + default void dropCarryLocal(){ + setCarryOf(null, this, null); + } + + /** + * Do not override unless absolutely necessary. + * Carries a unit. To drop a unit, call with {@code null}. + */ + default void carry(CarriableTrait unit){ + CallEntity.setCarryOf(this instanceof Player ? (Player) this : null, this, unit); + } } diff --git a/core/src/io/anuke/mindustry/entities/traits/InventoryTrait.java b/core/src/io/anuke/mindustry/entities/traits/InventoryTrait.java index 506ca6bd6a..c84eaea6b4 100644 --- a/core/src/io/anuke/mindustry/entities/traits/InventoryTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/InventoryTrait.java @@ -2,6 +2,6 @@ package io.anuke.mindustry.entities.traits; import io.anuke.mindustry.entities.UnitInventory; -public interface InventoryTrait { +public interface InventoryTrait{ UnitInventory getInventory(); } diff --git a/core/src/io/anuke/mindustry/entities/traits/RepairTrait.java b/core/src/io/anuke/mindustry/entities/traits/RepairTrait.java index 52e9a1c86c..4712730e4c 100644 --- a/core/src/io/anuke/mindustry/entities/traits/RepairTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/RepairTrait.java @@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.traits; import io.anuke.ucore.entities.trait.HealthTrait; //TODO implement -public interface RepairTrait extends TeamTrait { +public interface RepairTrait extends TeamTrait{ HealthTrait getRepairing(); diff --git a/core/src/io/anuke/mindustry/entities/traits/SaveTrait.java b/core/src/io/anuke/mindustry/entities/traits/SaveTrait.java index 94590db2fc..4e7009771e 100644 --- a/core/src/io/anuke/mindustry/entities/traits/SaveTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/SaveTrait.java @@ -2,6 +2,8 @@ package io.anuke.mindustry.entities.traits; import io.anuke.ucore.entities.trait.Entity; -/**Marks an entity as serializable.*/ +/** + * Marks an entity as serializable. + */ public interface SaveTrait extends Entity, TypeTrait, Saveable{ } diff --git a/core/src/io/anuke/mindustry/entities/traits/Saveable.java b/core/src/io/anuke/mindustry/entities/traits/Saveable.java index fee2a3123b..6f3950bcb0 100644 --- a/core/src/io/anuke/mindustry/entities/traits/Saveable.java +++ b/core/src/io/anuke/mindustry/entities/traits/Saveable.java @@ -4,7 +4,8 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -public interface Saveable { +public interface Saveable{ void writeSave(DataOutput stream) throws IOException; + void readSave(DataInput stream) throws IOException; } diff --git a/core/src/io/anuke/mindustry/entities/traits/ShooterTrait.java b/core/src/io/anuke/mindustry/entities/traits/ShooterTrait.java index c51eae473d..12df85dda1 100644 --- a/core/src/io/anuke/mindustry/entities/traits/ShooterTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/ShooterTrait.java @@ -7,6 +7,8 @@ import io.anuke.ucore.util.Timer; public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{ Timer getTimer(); + int getShootTimer(boolean left); + Weapon getWeapon(); } diff --git a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java index 1fd4a9daf0..55c1763b1f 100644 --- a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java @@ -3,8 +3,10 @@ package io.anuke.mindustry.entities.traits; import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.world.Tile; -public interface SpawnerTrait { +public interface SpawnerTrait{ Tile getTile(); + void updateSpawning(Unit unit); + float getSpawnProgress(); } diff --git a/core/src/io/anuke/mindustry/entities/traits/SyncTrait.java b/core/src/io/anuke/mindustry/entities/traits/SyncTrait.java index 471b3226c4..56bd43f948 100644 --- a/core/src/io/anuke/mindustry/entities/traits/SyncTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/SyncTrait.java @@ -10,18 +10,22 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.threads; -public interface SyncTrait extends Entity, TypeTrait { +public interface SyncTrait extends Entity, TypeTrait{ - /**Whether smoothing of entities is enabled when using multithreading; not yet implemented.*/ + /** + * Whether smoothing of entities is enabled when using multithreading; not yet implemented. + */ static boolean isSmoothing(){ return threads.isEnabled() && threads.getTPS() <= Gdx.graphics.getFramesPerSecond() / 2f; } - /**Sets the position of this entity and updated the interpolator.*/ + /** + * Sets the position of this entity and updated the interpolator. + */ default void setNet(float x, float y){ set(x, y); - if(getInterpolator() != null) { + if(getInterpolator() != null){ getInterpolator().target.set(x, y); getInterpolator().last.set(x, y); getInterpolator().pos.set(0, 0); @@ -30,9 +34,12 @@ public interface SyncTrait extends Entity, TypeTrait { } } - /**Interpolate entity position only. Override if you need to interpolate rotations or other values.*/ + /** + * Interpolate entity position only. Override if you need to interpolate rotations or other values. + */ default void interpolate(){ - if(getInterpolator() == null) throw new RuntimeException("This entity must have an interpolator to interpolate()!"); + if(getInterpolator() == null) + throw new RuntimeException("This entity must have an interpolator to interpolate()!"); getInterpolator().update(); @@ -40,17 +47,22 @@ public interface SyncTrait extends Entity, TypeTrait { setY(getInterpolator().pos.y); } - /**Return the interpolator used for smoothing the position. Optional.*/ + /** + * Return the interpolator used for smoothing the position. Optional. + */ default Interpolator getInterpolator(){ return null; } - /**Whether syncing is enabled for this entity; true by default.*/ + /** + * Whether syncing is enabled for this entity; true by default. + */ default boolean isSyncing(){ return true; } //Read and write sync data, usually position void write(DataOutput data) throws IOException; + void read(DataInput data, long time) throws IOException; } diff --git a/core/src/io/anuke/mindustry/entities/traits/TargetTrait.java b/core/src/io/anuke/mindustry/entities/traits/TargetTrait.java index 488f853feb..f63cca760f 100644 --- a/core/src/io/anuke/mindustry/entities/traits/TargetTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/TargetTrait.java @@ -1,16 +1,21 @@ package io.anuke.mindustry.entities.traits; import io.anuke.mindustry.game.Team; -import io.anuke.ucore.entities.trait.VelocityTrait; import io.anuke.ucore.entities.trait.PosTrait; +import io.anuke.ucore.entities.trait.VelocityTrait; -/**Base interface for targetable entities.*/ -public interface TargetTrait extends PosTrait, VelocityTrait { +/** + * Base interface for targetable entities. + */ +public interface TargetTrait extends PosTrait, VelocityTrait{ boolean isDead(); + Team getTeam(); - /**Whether this entity is a valid target.*/ + /** + * Whether this entity is a valid target. + */ default boolean isValid(){ return !isDead(); } diff --git a/core/src/io/anuke/mindustry/entities/traits/TeamTrait.java b/core/src/io/anuke/mindustry/entities/traits/TeamTrait.java index a02c3e902c..3c7cbf7dd3 100644 --- a/core/src/io/anuke/mindustry/entities/traits/TeamTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/TeamTrait.java @@ -3,6 +3,6 @@ package io.anuke.mindustry.entities.traits; import io.anuke.mindustry.game.Team; import io.anuke.ucore.entities.trait.Entity; -public interface TeamTrait extends Entity { +public interface TeamTrait extends Entity{ Team getTeam(); } diff --git a/core/src/io/anuke/mindustry/entities/traits/TypeTrait.java b/core/src/io/anuke/mindustry/entities/traits/TypeTrait.java index 076c2d05b3..9bde9509fc 100644 --- a/core/src/io/anuke/mindustry/entities/traits/TypeTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/TypeTrait.java @@ -4,12 +4,14 @@ import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.ObjectIntMap; import io.anuke.ucore.function.Supplier; -public interface TypeTrait { +public interface TypeTrait{ int[] lastRegisteredID = {0}; Array> registeredTypes = new Array<>(); ObjectIntMap> typeToID = new ObjectIntMap<>(); - /**Register and return a type ID. The supplier should return a fresh instace of that type.*/ + /** + * Register and return a type ID. The supplier should return a fresh instace of that type. + */ static void registerType(Class type, Supplier supplier){ if(typeToID.get(type, -1) != -1){ throw new RuntimeException("Type is already registered: '" + type + "'!"); @@ -18,10 +20,12 @@ public interface TypeTrait { registeredTypes.add(supplier); int result = lastRegisteredID[0]; typeToID.put(type, result); - lastRegisteredID[0] ++; + lastRegisteredID[0]++; } - /**Registers a syncable type by ID.*/ + /** + * Registers a syncable type by ID. + */ static Supplier getTypeByID(int id){ if(id == -1){ throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?"); @@ -29,11 +33,14 @@ public interface TypeTrait { return registeredTypes.get(id); } - /**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX. - * Do not override!*/ + /** + * Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX. + * Do not override! + */ default int getTypeID(){ int id = typeToID.get(getClass(), -1); - if(id == -1) throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?"); + if(id == -1) + throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?"); return id; } } diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index e78c3f07ea..51a2e11c9a 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -30,7 +30,10 @@ import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.*; +import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Geometry; +import io.anuke.ucore.util.Mathf; +import io.anuke.ucore.util.Timer; import java.io.DataInput; import java.io.DataOutput; @@ -39,376 +42,392 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; public abstract class BaseUnit extends Unit implements ShooterTrait{ - protected static int timerIndex = 0; + protected static int timerIndex = 0; - protected static final int timerTarget = timerIndex++; + protected static final int timerTarget = timerIndex++; - protected static final int timerShootLeft = timerIndex++; - protected static final int timerShootRight = timerIndex++; + protected static final int timerShootLeft = timerIndex++; + protected static final int timerShootRight = timerIndex++; - protected UnitType type; - protected Timer timer = new Timer(5); - protected StateMachine state = new StateMachine(); - protected TargetTrait target; + protected UnitType type; + protected Timer timer = new Timer(5); + protected StateMachine state = new StateMachine(); + protected TargetTrait target; - protected boolean isWave; - protected Squad squad; - protected int spawner; + protected boolean isWave; + protected Squad squad; + protected int spawner; - /**Initialize the type and team of this unit. Only call once!*/ - public void init(UnitType type, Team team){ - if(this.type != null) throw new RuntimeException("This unit is already initialized!"); + /** + * internal constructor used for deserialization, DO NOT USE + */ + public BaseUnit(){ + } - this.type = type; - this.team = team; - } + @Remote(called = Loc.server, in = In.entities) + public static void onUnitDeath(BaseUnit unit){ + if(unit == null) return; - public void setSpawner(Tile tile) { - this.spawner = tile.packedPosition(); - } + if(Net.server() || !Net.active()){ + UnitDrops.dropItems(unit); + } - public UnitType getType() { - return type; - } + float explosiveness = 2f + (unit.inventory.hasItem() ? unit.inventory.getItem().item.explosiveness * unit.inventory.getItem().amount : 0f); + float flammability = (unit.inventory.hasItem() ? unit.inventory.getItem().item.flammability * unit.inventory.getItem().amount : 0f); + Damage.dynamicExplosion(unit.x, unit.y, flammability, explosiveness, 0f, unit.getSize() / 2f, Palette.darkFlame); - /**internal constructor used for deserialization, DO NOT USE*/ - public BaseUnit(){} + unit.onSuperDeath(); - /**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/ - public void setWave(){ - isWave = true; - } + ScorchDecal.create(unit.x, unit.y); + Effects.effect(ExplosionFx.explosion, unit); + Effects.shake(2f, 2f, unit); - public void setSquad(Squad squad) { - this.squad = squad; - squad.units ++; - } + //must run afterwards so the unit's group is not null + threads.runDelay(unit::remove); + } - public void rotate(float angle){ - rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed); - } + /** + * Initialize the type and team of this unit. Only call once! + */ + public void init(UnitType type, Team team){ + if(this.type != null) throw new RuntimeException("This unit is already initialized!"); - public boolean targetHasFlag(BlockFlag flag){ - return target instanceof TileEntity && - ((TileEntity)target).tile.block().flags.contains(flag); - } + this.type = type; + this.team = team; + } - public void updateRespawning(){ - if(spawner == -1) return; + public UnitType getType(){ + return type; + } - Tile tile = world.tile(spawner); - if(tile != null && tile.entity != null){ - if(tile.entity instanceof SpawnerTrait){ - ((SpawnerTrait) tile.entity).updateSpawning(this); + public Tile getSpawner(){ + return world.tile(spawner); + } + + public void setSpawner(Tile tile){ + this.spawner = tile.packedPosition(); + } + + /** + * Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo. + */ + public void setWave(){ + isWave = true; + } + + public void setSquad(Squad squad){ + this.squad = squad; + squad.units++; + } + + public void rotate(float angle){ + rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed); + } + + public boolean targetHasFlag(BlockFlag flag){ + return target instanceof TileEntity && + ((TileEntity) target).tile.block().flags.contains(flag); + } + + public void updateRespawning(){ + if(spawner == -1) return; + + Tile tile = world.tile(spawner); + if(tile != null && tile.entity != null){ + if(tile.entity instanceof SpawnerTrait){ + ((SpawnerTrait) tile.entity).updateSpawning(this); } - }else{ - spawner = -1; - } - } - - public void setState(UnitState state){ - this.state.set(state); - } - - public void retarget(Runnable run){ - if(timer.get(timerTarget, 20)){ - run.run(); - } - } - - /**Only runs when the unit has a target.*/ - public void behavior(){ - - } - - public void updateTargeting(){ - if(target == null || (target instanceof Unit && (target.isDead() || target.getTeam() == team)) - || (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){ - target = null; - } - } - public void targetClosestAllyFlag(BlockFlag flag){ - Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag)); - if (target != null) this.target = target.entity; - } - - public void targetClosestEnemyFlag(BlockFlag flag){ - Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, flag)); - if (target != null) this.target = target.entity; - } - - public void targetClosest(){ - target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange()); - } - - public TileEntity getClosestEnemyCore(){ - if(Vars.state.teams.has(team)){ - ObjectSet datas = Vars.state.teams.enemyDataOf(team); - - for(TeamData data : datas){ - Tile tile = Geometry.findClosest(x, y, data.cores); - if(tile != null){ - return tile.entity; - } - } - } - return null; - } - - public UnitState getStartState(){ - return null; - } - - protected void drawItems(){ - float backTrns = 4f, itemSize = 5f; - if(inventory.hasItem()){ - ItemStack stack = inventory.getItem(); - int stored = Mathf.clamp(stack.amount / 6, 1, 8); - - for(int i = 0; i < stored; i ++) { - float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 60f); - float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 3, 1f) - 1f; - Draw.rect(stack.item.region, - x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT), - y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT), - itemSize, itemSize, rotation); - } - } - } - - @Override - public boolean isValid() { - return super.isValid() && isAdded(); - } - - @Override - public Timer getTimer() { - return timer; - } - - @Override - public int getShootTimer(boolean left) { - return left ? timerShootLeft : timerShootRight; - } - - @Override - public Weapon getWeapon() { - return type.weapon; - } - - @Override - public TextureRegion getIconRegion() { - return type.iconRegion; - } - - @Override - public int getItemCapacity() { - return type.itemCapacity; - } - - @Override - public int getAmmoCapacity() { - return type.ammoCapacity; - } - - @Override - public boolean isInfiniteAmmo() { - return isWave; - } - - @Override - public void interpolate() { - super.interpolate(); - - if(interpolator.values.length > 0){ - rotation = interpolator.values[0]; - } - } - - @Override - public float maxHealth() { - return type.health; - } - - @Override - public float getArmor() { - return type.armor; - } - - @Override - public boolean acceptsAmmo(Item item) { - return getWeapon().getAmmoType(item) != null && inventory.canAcceptAmmo(getWeapon().getAmmoType(item)); - } - - @Override - public void addAmmo(Item item) { - inventory.addAmmo(getWeapon().getAmmoType(item)); - } - - @Override - public float getSize() { - return 8; - } - - @Override - public float getMass() { - return type.mass; - } - - @Override - public boolean isFlying() { - return type.isFlying; - } - - @Override - public void update(){ - if(hitTime > 0){ - hitTime -= Timers.delta(); - } - - if(hitTime < 0) hitTime = 0; - - if(isDead()){ - updateRespawning(); - return; - } - - if(Net.client()){ - interpolate(); - status.update(this); - return; - } - - avoidOthers(8f); - - if(squad != null){ - squad.update(); - } - - updateTargeting(); - - state.update(); - updateVelocityStatus(type.drag, type.maxVelocity); - - if(target != null) behavior(); - - if(!isWave) { - x = Mathf.clamp(x, 0, world.width() * tilesize); - y = Mathf.clamp(y, 0, world.height() * tilesize); - } - } - - @Override - public void draw(){ - - } - - @Override - public void drawUnder(){ - - } - - @Override - public void drawOver(){ - - } - - @Override - public void removed() { - Tile tile = world.tile(spawner); - - if(tile != null && tile.entity instanceof UnitFactoryEntity){ - UnitFactoryEntity factory = (UnitFactoryEntity)tile.entity; - factory.hasSpawned = false; - } - - spawner = -1; - } - - @Override - public float drawSize(){ - return 14; - } - - @Override - public void onDeath(){ - CallEntity.onUnitDeath(this); - } - - @Override - public void added(){ - hitbox.setSize(type.hitsize); - hitboxTile.setSize(type.hitsizeTile); - state.set(getStartState()); - - health(maxHealth()); - } - - @Override - public EntityGroup targetGroup() { - return unitGroups[team.ordinal()]; - } - - @Override - public void writeSave(DataOutput stream) throws IOException { - super.writeSave(stream); - stream.writeByte(type.id); - stream.writeBoolean(isWave); - stream.writeInt(spawner); - } - - @Override - public void readSave(DataInput stream) throws IOException { - super.readSave(stream); - byte type = stream.readByte(); - this.isWave = stream.readBoolean(); - this.spawner = stream.readInt(); - - this.type = UnitType.getByID(type); - add(); - } - - @Override - public void write(DataOutput data) throws IOException{ - super.writeSave(data); - data.writeByte(type.id); - data.writeInt(spawner); - } - - @Override - public void read(DataInput data, long time) throws IOException{ - float lastx = x, lasty = y, lastrot = rotation; - super.readSave(data); - this.type = UnitType.getByID(data.readByte()); - this.spawner = data.readInt(); - - interpolator.read(lastx, lasty, x, y, time, rotation); - rotation = lastrot; - } - - public void onSuperDeath(){ - super.onDeath(); - } - - @Remote(called = Loc.server, in = In.entities) - public static void onUnitDeath(BaseUnit unit){ - if(unit == null) return; - - if(Net.server() || !Net.active()){ - UnitDrops.dropItems(unit); - } - - float explosiveness = 2f + (unit.inventory.hasItem() ? unit.inventory.getItem().item.explosiveness * unit.inventory.getItem().amount : 0f); - float flammability = (unit.inventory.hasItem() ? unit.inventory.getItem().item.flammability * unit.inventory.getItem().amount : 0f); - Damage.dynamicExplosion(unit.x, unit.y, flammability, explosiveness, 0f, unit.getSize()/2f, Palette.darkFlame); - - unit.onSuperDeath(); - - ScorchDecal.create(unit.x, unit.y); - Effects.effect(ExplosionFx.explosion, unit); - Effects.shake(2f, 2f, unit); - - //must run afterwards so the unit's group is not null - threads.runDelay(unit::remove); - } + }else{ + spawner = -1; + } + } + + public void setState(UnitState state){ + this.state.set(state); + } + + public void retarget(Runnable run){ + if(timer.get(timerTarget, 20)){ + run.run(); + } + } + + /** + * Only runs when the unit has a target. + */ + public void behavior(){ + + } + + public void updateTargeting(){ + if(target == null || (target instanceof Unit && (target.isDead() || target.getTeam() == team)) + || (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){ + target = null; + } + } + + public void targetClosestAllyFlag(BlockFlag flag){ + Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag)); + if(target != null) this.target = target.entity; + } + + public void targetClosestEnemyFlag(BlockFlag flag){ + Tile target = Geometry.findClosest(x, y, world.indexer().getEnemy(team, flag)); + if(target != null) this.target = target.entity; + } + + public void targetClosest(){ + target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange()); + } + + public TileEntity getClosestEnemyCore(){ + if(Vars.state.teams.has(team)){ + ObjectSet datas = Vars.state.teams.enemyDataOf(team); + + for(TeamData data : datas){ + Tile tile = Geometry.findClosest(x, y, data.cores); + if(tile != null){ + return tile.entity; + } + } + } + return null; + } + + public UnitState getStartState(){ + return null; + } + + protected void drawItems(){ + float backTrns = 4f, itemSize = 5f; + if(inventory.hasItem()){ + ItemStack stack = inventory.getItem(); + int stored = Mathf.clamp(stack.amount / 6, 1, 8); + + for(int i = 0; i < stored; i++){ + float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 60f); + float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 3, 1f) - 1f; + Draw.rect(stack.item.region, + x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT), + y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT), + itemSize, itemSize, rotation); + } + } + } + + @Override + public boolean isValid(){ + return super.isValid() && isAdded(); + } + + @Override + public Timer getTimer(){ + return timer; + } + + @Override + public int getShootTimer(boolean left){ + return left ? timerShootLeft : timerShootRight; + } + + @Override + public Weapon getWeapon(){ + return type.weapon; + } + + @Override + public TextureRegion getIconRegion(){ + return type.iconRegion; + } + + @Override + public int getItemCapacity(){ + return type.itemCapacity; + } + + @Override + public int getAmmoCapacity(){ + return type.ammoCapacity; + } + + @Override + public boolean isInfiniteAmmo(){ + return isWave; + } + + @Override + public void interpolate(){ + super.interpolate(); + + if(interpolator.values.length > 0){ + rotation = interpolator.values[0]; + } + } + + @Override + public float maxHealth(){ + return type.health; + } + + @Override + public float getArmor(){ + return type.armor; + } + + @Override + public boolean acceptsAmmo(Item item){ + return getWeapon().getAmmoType(item) != null && inventory.canAcceptAmmo(getWeapon().getAmmoType(item)); + } + + @Override + public void addAmmo(Item item){ + inventory.addAmmo(getWeapon().getAmmoType(item)); + } + + @Override + public float getSize(){ + return 8; + } + + @Override + public float getMass(){ + return type.mass; + } + + @Override + public boolean isFlying(){ + return type.isFlying; + } + + @Override + public void update(){ + if(hitTime > 0){ + hitTime -= Timers.delta(); + } + + if(hitTime < 0) hitTime = 0; + + if(isDead()){ + updateRespawning(); + return; + } + + if(Net.client()){ + interpolate(); + status.update(this); + return; + } + + if(!Net.client()){ + avoidOthers(8f); + } + + if(squad != null){ + squad.update(); + } + + updateTargeting(); + + state.update(); + updateVelocityStatus(type.drag, type.maxVelocity); + + if(target != null) behavior(); + + if(!isWave){ + x = Mathf.clamp(x, 0, world.width() * tilesize); + y = Mathf.clamp(y, 0, world.height() * tilesize); + } + } + + @Override + public void draw(){ + + } + + @Override + public void drawUnder(){ + + } + + @Override + public void drawOver(){ + + } + + @Override + public void removed(){ + Tile tile = world.tile(spawner); + + if(tile != null && tile.entity instanceof UnitFactoryEntity){ + UnitFactoryEntity factory = (UnitFactoryEntity) tile.entity; + factory.hasSpawned = false; + } + + spawner = -1; + } + + @Override + public float drawSize(){ + return 14; + } + + @Override + public void onDeath(){ + CallEntity.onUnitDeath(this); + } + + @Override + public void added(){ + hitbox.setSize(type.hitsize); + hitboxTile.setSize(type.hitsizeTile); + state.set(getStartState()); + + health(maxHealth()); + } + + @Override + public EntityGroup targetGroup(){ + return unitGroups[team.ordinal()]; + } + + @Override + public void writeSave(DataOutput stream) throws IOException{ + super.writeSave(stream); + stream.writeByte(type.id); + stream.writeBoolean(isWave); + stream.writeInt(spawner); + } + + @Override + public void readSave(DataInput stream) throws IOException{ + super.readSave(stream); + byte type = stream.readByte(); + this.isWave = stream.readBoolean(); + this.spawner = stream.readInt(); + + this.type = UnitType.getByID(type); + add(); + } + + @Override + public void write(DataOutput data) throws IOException{ + super.writeSave(data); + data.writeByte(type.id); + data.writeInt(spawner); + } + + @Override + public void read(DataInput data, long time) throws IOException{ + float lastx = x, lasty = y, lastrot = rotation; + super.readSave(data); + this.type = UnitType.getByID(data.readByte()); + this.spawner = data.readInt(); + + interpolator.read(lastx, lasty, x, y, time, rotation); + rotation = lastrot; + } + + public void onSuperDeath(){ + super.onDeath(); + } } diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java index ebb3eb2287..1b2df0d94c 100644 --- a/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnit.java @@ -27,28 +27,124 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ protected Trail trail = new Trail(8); protected CarriableTrait carrying; + protected final UnitState + + resupply = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ + state.set(attack); + }else if(!targetHasFlag(BlockFlag.resupplyPoint)){ + retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint)); + }else{ + circle(20f); + } + } + }, + idle = new UnitState(){ + public void update(){ + retarget(() -> { + targetClosest(); + targetClosestEnemyFlag(BlockFlag.target); + + if(target != null){ + setState(attack); + } + }); + + target = getClosestCore(); + if(target != null){ + circle(50f); + } + velocity.scl(0.8f); + } + }, + attack = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + if(Units.invalidateTarget(target, team, x, y)){ + target = null; + } + + if(!inventory.hasAmmo()){ + state.set(resupply); + }else if(target == null){ + retarget(() -> { + targetClosest(); + targetClosestEnemyFlag(BlockFlag.target); + targetClosestEnemyFlag(BlockFlag.producer); + + if(target == null){ + setState(idle); + } + }); + }else{ + attack(150f); + + if((Mathf.angNear(angleTo(target), rotation, 15f) || !inventory.getAmmo().bullet.keepVelocity) //bombers don't care about rotation + && distanceTo(target) < inventory.getAmmo().getRange()){ + AmmoType ammo = inventory.getAmmo(); + inventory.useAmmo(); + + Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.bullet.speed); + + getWeapon().update(FlyingUnit.this, to.x, to.y); + } + } + } + }, + retreat = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + if(health >= maxHealth()){ + state.set(attack); + }else if(!targetHasFlag(BlockFlag.repair)){ + retarget(() -> { + Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)); + if(target != null) FlyingUnit.this.target = target.entity; + }); + }else{ + circle(20f); + } + } + }; + //instantiation only public FlyingUnit(){ } @Override - public CarriableTrait getCarry() { + public void drawShadow(){ + Draw.rect(type.region, x + elevation * elevationScale, y - elevation * elevationScale, rotation - 90); + } + + @Override + public CarriableTrait getCarry(){ return carrying; } @Override - public void setCarry(CarriableTrait unit) { + public void setCarry(CarriableTrait unit){ this.carrying = unit; } @Override - public float getCarryWeight() { + public float getCarryWeight(){ return type.carryWeight; } @Override - public void update() { + public void update(){ super.update(); updateRotation(); @@ -59,7 +155,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ } @Override - public void draw() { + public void draw(){ Draw.alpha(hitTime / hitDuration); Draw.rect(type.name, x, y, rotation - 90); @@ -70,12 +166,12 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ } @Override - public void drawOver() { - trail.draw(Palette.lightTrail, Palette.lightTrail, 5f); + public void drawOver(){ + trail.draw(Palette.lightTrail, 5f); } @Override - public void behavior() { + public void behavior(){ if(health <= health * type.retreatPercent && !isWave && Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ setState(retreat); @@ -93,7 +189,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ } @Override - public float drawSize() { + public float drawSize(){ return 60; } @@ -103,7 +199,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f); y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f); - if (velocity.len() <= 0.2f) { + if(velocity.len() <= 0.2f){ rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f); } } @@ -122,7 +218,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ vec.set(target.getX() - x, target.getY() - y); if(vec.len() < circleLength){ - vec.rotate((circleLength-vec.len())/circleLength * 180f); + vec.rotate((circleLength - vec.len()) / circleLength * 180f); } vec.setLength(speed * Timers.delta()); @@ -135,7 +231,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ vec.set(target.getX() - x, target.getY() - y); - float length = Mathf.clamp((distanceTo(target) - circleLength)/100f, -1f, 1f); + float length = Mathf.clamp((distanceTo(target) - circleLength) / 100f, -1f, 1f); vec.setLength(type.speed * Timers.delta() * length); if(length < 0) vec.rotate(180f); @@ -152,102 +248,11 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{ if(diff > 100f && vec.len() < circleLength){ vec.setAngle(velocity.angle()); }else{ - vec.setAngle(Mathf.slerpDelta(velocity.angle(), vec.angle(), 0.44f)); + vec.setAngle(Mathf.slerpDelta(velocity.angle(), vec.angle(), 0.44f)); } - vec.setLength(type.speed*Timers.delta()); + vec.setLength(type.speed * Timers.delta()); velocity.add(vec); } - - public final UnitState - - resupply = new UnitState(){ - public void entered() { - target = null; - } - - public void update() { - if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ - state.set(attack); - }else if(!targetHasFlag(BlockFlag.resupplyPoint)){ - retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint)); - }else{ - circle(20f); - } - } - }, - idle = new UnitState() { - public void update() { - retarget(() -> { - targetClosest(); - targetClosestEnemyFlag(BlockFlag.target); - - if(target != null){ - setState(attack); - } - }); - - target = getClosestCore(); - if(target != null){ - circle(50f); - } - velocity.scl(0.8f); - } - }, - attack = new UnitState(){ - public void entered() { - target = null; - } - - public void update() { - if(Units.invalidateTarget(target, team, x, y)){ - target = null; - } - - if(!inventory.hasAmmo()) { - state.set(resupply); - }else if (target == null){ - retarget(() -> { - targetClosest(); - targetClosestEnemyFlag(BlockFlag.target); - targetClosestEnemyFlag(BlockFlag.producer); - - if(target == null){ - setState(idle); - } - }); - }else{ - attack(150f); - - if ((Mathf.angNear(angleTo(target), rotation, 15f) || !inventory.getAmmo().bullet.keepVelocity) //bombers don't care about rotation - && distanceTo(target) < inventory.getAmmo().getRange()) { - AmmoType ammo = inventory.getAmmo(); - inventory.useAmmo(); - - Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.bullet.speed); - - getWeapon().update(FlyingUnit.this, to.x, to.y); - } - } - } - }, - retreat = new UnitState() { - public void entered() { - target = null; - } - - public void update() { - if(health >= maxHealth()){ - state.set(attack); - }else if(!targetHasFlag(BlockFlag.repair)){ - retarget(() -> { - Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)); - if (target != null) FlyingUnit.this.target = target.entity; - }); - }else{ - circle(20f); - } - } - }; } diff --git a/core/src/io/anuke/mindustry/entities/units/GroundUnit.java b/core/src/io/anuke/mindustry/entities/units/GroundUnit.java index 0ce352809f..5dba19a82d 100644 --- a/core/src/io/anuke/mindustry/entities/units/GroundUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/GroundUnit.java @@ -26,24 +26,101 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.world; -public abstract class GroundUnit extends BaseUnit { +public abstract class GroundUnit extends BaseUnit{ protected static Translator vec = new Translator(); protected float walkTime; protected float baseRotation; + public final UnitState + + resupply = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint)); + + if(tile != null && distanceTo(tile) > 40){ + moveAwayFromCore(); + } + + //TODO move toward resupply point + if(isWave || inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ + state.set(attack); + } + } + }, + attack = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + TileEntity core = getClosestEnemyCore(); + float dst = core == null ? 0 : distanceTo(core); + + if(core != null && inventory.hasAmmo() && dst < inventory.getAmmo().getRange() / 1.1f){ + target = core; + }else{ + retarget(() -> targetClosest()); + } + + if(!inventory.hasAmmo()){ + state.set(resupply); + }else if(target != null){ + if(core != null){ + if(dst > inventory.getAmmo().getRange() * 0.5f){ + moveToCore(); + } + + }else{ + moveToCore(); + } + + if(distanceTo(target) < inventory.getAmmo().getRange()){ + rotate(angleTo(target)); + + if(Mathf.angNear(angleTo(target), rotation, 13f)){ + AmmoType ammo = inventory.getAmmo(); + + Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.bullet.speed); + + getWeapon().update(GroundUnit.this, to.x, to.y); + } + } + + }else{ + moveToCore(); + } + } + }, + retreat = new UnitState(){ + public void entered(){ + target = null; + } + + public void update(){ + if(health >= health){ + state.set(attack); + } + + moveAwayFromCore(); + } + }; protected Weapon weapon; @Override - public void init(UnitType type, Team team) { + public void init(UnitType type, Team team){ super.init(type, team); this.weapon = type.weapon; } @Override - public void interpolate() { + public void interpolate(){ super.interpolate(); - if(interpolator.values.length > 1) { + if(interpolator.values.length > 1){ baseRotation = interpolator.values[1]; } } @@ -57,12 +134,12 @@ public abstract class GroundUnit extends BaseUnit { } @Override - public UnitState getStartState() { + public UnitState getStartState(){ return resupply; } @Override - public void update() { + public void update(){ super.update(); if(!velocity.isZero(0.0001f) && (target == null || !inventory.hasAmmo() || (inventory.hasAmmo() && distanceTo(target) > inventory.getAmmoRange()))){ @@ -71,12 +148,16 @@ public abstract class GroundUnit extends BaseUnit { } @Override - public Weapon getWeapon() { + public Weapon getWeapon(){ return weapon; } + public void setWeapon(Weapon weapon){ + this.weapon = weapon; + } + @Override - public void draw() { + public void draw(){ Draw.alpha(hitTime / hitDuration); float walktime = walkTime; @@ -89,25 +170,25 @@ public abstract class GroundUnit extends BaseUnit { Draw.tint(Color.WHITE, floor.liquidColor, 0.5f); } - for (int i : Mathf.signs) { + for(int i : Mathf.signs){ Draw.rect(type.legRegion, x + Angles.trnsx(baseRotation, ft * i), y + Angles.trnsy(baseRotation, ft * i), 12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90); } - if(floor.isLiquid) { + if(floor.isLiquid){ Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f); - }else { + }else{ Draw.tint(Color.WHITE); } - Draw.rect(type.baseRegion, x, y, baseRotation- 90); + Draw.rect(type.baseRegion, x, y, baseRotation - 90); - Draw.rect(type.region, x, y, rotation -90); + Draw.rect(type.region, x, y, rotation - 90); - for (int i : Mathf.signs) { - float tra = rotation - 90, trY = - weapon.getRecoil(this, i > 0) + type.weaponOffsetY; + for(int i : Mathf.signs){ + float tra = rotation - 90, trY = -weapon.getRecoil(this, i > 0) + type.weaponOffsetY; float w = i > 0 ? -12 : 12; Draw.rect(weapon.equipRegion, x + Angles.trnsx(tra, type.weaponOffsetX * i, trY), @@ -120,35 +201,35 @@ public abstract class GroundUnit extends BaseUnit { } @Override - public void behavior() { + public void behavior(){ if(health <= health * type.retreatPercent && !isWave){ setState(retreat); } } @Override - public void updateTargeting() { + public void updateTargeting(){ super.updateTargeting(); - if(Units.invalidateTarget(target, team, x, y, Float.MAX_VALUE)){ + if(Units.invalidateTarget(target, team, x, y, Float.MAX_VALUE)){ target = null; } } @Override - public void write(DataOutput data) throws IOException { + public void write(DataOutput data) throws IOException{ super.write(data); data.writeByte(weapon.id); } @Override - public void read(DataInput data, long time) throws IOException { + public void read(DataInput data, long time) throws IOException{ super.read(data, time); weapon = Upgrade.getByID(data.readByte()); } @Override - public void writeSave(DataOutput stream) throws IOException { + public void writeSave(DataOutput stream) throws IOException{ stream.writeByte(weapon.id); super.writeSave(stream); } @@ -159,10 +240,6 @@ public abstract class GroundUnit extends BaseUnit { super.readSave(stream); } - public void setWeapon(Weapon weapon){ - this.weapon = weapon; - } - protected void moveToCore(){ Tile tile = world.tileWorld(x, y); if(tile == null) return; @@ -189,82 +266,4 @@ public abstract class GroundUnit extends BaseUnit { walkTime += Timers.delta(); velocity.add(vec); } - - public final UnitState - - resupply = new UnitState(){ - public void entered() { - target = null; - } - - public void update() { - Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint)); - - if (tile != null && distanceTo(tile) > 40) { - moveAwayFromCore(); - } - - //TODO move toward resupply point - if(isWave || inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ - state.set(attack); - } - } - }, - attack = new UnitState(){ - public void entered() { - target = null; - } - - public void update() { - TileEntity core = getClosestEnemyCore(); - float dst = core == null ? 0 :distanceTo(core); - - if(core != null && inventory.hasAmmo() && dst < inventory.getAmmo().getRange()/1.1f){ - target = core; - }else { - retarget(() -> targetClosest()); - } - - if(!inventory.hasAmmo()) { - state.set(resupply); - }else if(target != null){ - if(core != null){ - if(dst > inventory.getAmmo().getRange() * 0.5f){ - moveToCore(); - } - - }else{ - moveToCore(); - } - - if(distanceTo(target) < inventory.getAmmo().getRange()){ - rotate(angleTo(target)); - - if (Mathf.angNear(angleTo(target), rotation, 13f)) { - AmmoType ammo = inventory.getAmmo(); - - Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.bullet.speed); - - getWeapon().update(GroundUnit.this, to.x, to.y); - } - } - - }else{ - moveToCore(); - } - } - }, - retreat = new UnitState() { - public void entered() { - target = null; - } - - public void update() { - if(health >= health){ - state.set(attack); - } - - moveAwayFromCore(); - } - }; } diff --git a/core/src/io/anuke/mindustry/entities/units/Squad.java b/core/src/io/anuke/mindustry/entities/units/Squad.java index 41ad5f9d58..1068de0a6b 100644 --- a/core/src/io/anuke/mindustry/entities/units/Squad.java +++ b/core/src/io/anuke/mindustry/entities/units/Squad.java @@ -5,9 +5,11 @@ import io.anuke.ucore.util.Translator; import static io.anuke.mindustry.Vars.threads; -/**Used to group entities together, for formations and such. - * Usually, squads are used by units spawned in the same wave.*/ -public class Squad { +/** + * Used to group entities together, for formations and such. + * Usually, squads are used by units spawned in the same wave. + */ +public class Squad{ public Vector2 direction = new Translator(); public int units; diff --git a/core/src/io/anuke/mindustry/entities/units/StateMachine.java b/core/src/io/anuke/mindustry/entities/units/StateMachine.java index 082f7d114f..a676716693 100644 --- a/core/src/io/anuke/mindustry/entities/units/StateMachine.java +++ b/core/src/io/anuke/mindustry/entities/units/StateMachine.java @@ -1,13 +1,13 @@ package io.anuke.mindustry.entities.units; -public class StateMachine { +public class StateMachine{ private UnitState state; public void update(){ if(state != null) state.update(); } - public void set( UnitState next){ + public void set(UnitState next){ if(next == state) return; if(state != null) state.exited(); this.state = next; diff --git a/core/src/io/anuke/mindustry/entities/units/UnitDrops.java b/core/src/io/anuke/mindustry/entities/units/UnitDrops.java index c931cd875c..2ba240de70 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitDrops.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitDrops.java @@ -6,7 +6,7 @@ import io.anuke.mindustry.entities.effect.ItemDrop; import io.anuke.mindustry.type.Item; import io.anuke.ucore.util.Mathf; -public class UnitDrops { +public class UnitDrops{ private static final int maxItems = 200; private static Item[] dropTable; @@ -19,7 +19,7 @@ public class UnitDrops { dropTable = new Item[]{Items.tungsten, Items.lead, Items.carbide}; } - for (int i = 0; i < 3; i++) { + for(int i = 0; i < 3; i++){ for(Item item : dropTable){ if(Mathf.chance(0.03)){ int amount = Mathf.random(20, 40); diff --git a/core/src/io/anuke/mindustry/entities/units/UnitState.java b/core/src/io/anuke/mindustry/entities/units/UnitState.java index c11ce3aa8b..5c5f9c64a8 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitState.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitState.java @@ -1,7 +1,12 @@ package io.anuke.mindustry.entities.units; -public interface UnitState { - default void entered(){} - default void exited(){} - default void update(){} +public interface UnitState{ + default void entered(){ + } + + default void exited(){ + } + + default void update(){ + } } diff --git a/core/src/io/anuke/mindustry/entities/units/UnitType.java b/core/src/io/anuke/mindustry/entities/units/UnitType.java index d03396120b..848ef6d372 100644 --- a/core/src/io/anuke/mindustry/entities/units/UnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/UnitType.java @@ -18,12 +18,9 @@ import io.anuke.ucore.util.Bundles; public class UnitType implements UnlockableContent{ private static byte lastid = 0; private static Array types = new Array<>(); - - protected final Supplier constructor; - public final String name; public final byte id; - + protected final Supplier constructor; public float health = 60; public float hitsize = 5f; public float hitsizeTile = 4f; @@ -57,44 +54,52 @@ public class UnitType implements UnlockableContent{ TypeTrait.registerType(type, mainConstructor); } + public static UnitType getByID(byte id){ + return types.get(id); + } + + public static Array all(){ + return types; + } + @Override - public void displayInfo(Table table) { + public void displayInfo(Table table){ ContentDisplay.displayUnit(table, this); } @Override - public String localizedName() { + public String localizedName(){ return Bundles.get("unit." + name + ".name"); } @Override - public TextureRegion getContentIcon() { + public TextureRegion getContentIcon(){ return iconRegion; } @Override - public void load() { + public void load(){ iconRegion = Draw.region("unit-icon-" + name); region = Draw.region(name); - if(!isFlying) { + if(!isFlying){ legRegion = Draw.region(name + "-leg"); baseRegion = Draw.region(name + "-base"); } } @Override - public String getContentTypeName() { + public String getContentTypeName(){ return "unit-type"; } @Override - public String getContentName() { + public String getContentName(){ return name; } @Override - public Array getAll() { + public Array getAll(){ return types; } @@ -103,12 +108,4 @@ public class UnitType implements UnlockableContent{ unit.init(this, team); return unit; } - - public static UnitType getByID(byte id){ - return types.get(id); - } - - public static Array all(){ - return types; - } } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Drone.java b/core/src/io/anuke/mindustry/entities/units/types/Drone.java index 89d7885892..f51229f6cf 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Drone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Drone.java @@ -16,6 +16,7 @@ import io.anuke.mindustry.entities.units.UnitState; import io.anuke.mindustry.game.EventType.BlockBuildEvent; import io.anuke.mindustry.gen.CallEntity; import io.anuke.mindustry.graphics.Palette; +import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.Tile; @@ -39,7 +40,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class Drone extends FlyingUnit implements BuilderTrait { +public class Drone extends FlyingUnit implements BuilderTrait{ protected static ObjectSet toMine; protected static float discoverRange = 120f; protected static boolean initialized; @@ -48,189 +49,18 @@ public class Drone extends FlyingUnit implements BuilderTrait { protected Tile mineTile; protected Queue placeQueue = new ThreadQueue<>(); - /**Initialize placement event notifier system. - * Static initialization is to be avoided, thus, this is done lazily.*/ - private static void initEvents(){ - if(initialized) return; - - toMine = ObjectSet.with(Items.lead, Items.tungsten); - - Events.on(BlockBuildEvent.class, (team, tile) -> { - EntityGroup group = unitGroups[team.ordinal()]; - - if(!(tile.entity instanceof BuildEntity)) return; - BuildEntity entity = tile.entity(); - - for(BaseUnit unit : group.all()){ - if(unit instanceof Drone){ - ((Drone) unit).notifyPlaced(entity); - } - } - }); - - initialized = true; - } - - { - initEvents(); - } - - private void notifyPlaced(BuildEntity entity){ - float timeToBuild = entity.recipe.cost; - float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0); - - if(dist / type.maxVelocity < timeToBuild * 0.9f){ - //CallEntity.onDroneBeginBuild(this, entity.tile, entity.recipe); - target = entity; - setState(build); - } - } - - @Override - public float getBuildPower(Tile tile) { - return type.buildPower; - } - - @Override - public float getMinePower() { - return type.minePower; - } - - @Override - public Queue getPlaceQueue() { - return placeQueue; - } - - @Override - public Tile getMineTile() { - return mineTile; - } - - @Override - public void setMineTile(Tile tile) { - mineTile = tile; - } - - @Override - public void update() { - super.update(); - - x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f); - y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f); - - updateBuilding(this); - } - - @Override - protected void updateRotation() { - if(target != null && (state.is(repair) || state.is(mine))){ - rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f); - }else{ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f); - } - - if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){ - rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f); - } - } - - @Override - public void behavior() { - if(health <= health * type.retreatPercent && - Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ - setState(retreat); - } - } - - @Override - public UnitState getStartState() { - return repair; - } - - @Override - public void drawOver() { - trail.draw(Palette.lightTrail, Palette.lightTrail, 3f); - - TargetTrait entity = target; - - if(entity instanceof TileEntity && state.is(repair)){ - float len = 5f; - Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f)); - Shapes.laser("beam", "beam-end", - x + Angles.trnsx(rotation, len), - y + Angles.trnsy(rotation, len), - entity.getX(), entity.getY()); - Draw.color(); - } - - drawBuilding(this); - } - - @Override - public float drawSize() { - return isBuilding() ? placeDistance*2f : 30f; - } - - @Override - public float getAmmoFraction() { - return inventory.getItem().amount / (float)type.itemCapacity; - } - - protected void findItem(){ - TileEntity entity = getClosestCore(); - if(entity == null){ - return; - } - targetItem = Mathf.findMin(toMine, (a, b) -> -Integer.compare(entity.items.getItem(a), entity.items.getItem(b))); - } - - protected boolean findItemDrop(){ - TileEntity core = getClosestCore(); - - if(core == null) return false; - - //find nearby dropped items to pick up if applicable - ItemDrop drop = EntityPhysics.getClosest(itemGroup, x, y, 60f, - item -> core.tile.block().acceptStack(item.getItem(), item.getAmount(), core.tile, Drone.this) == item.getAmount() && - inventory.canAcceptItem(item.getItem(), 1)); - if(drop != null){ - setState(pickup); - target = drop; - return true; - } - return false; - } - - @Override - public void write(DataOutput data) throws IOException { - super.write(data); - data.writeInt(mineTile == null ? -1 : mineTile.packedPosition()); - writeBuilding(data); - } - - @Override - public void read(DataInput data, long time) throws IOException { - super.read(data, time); - int mined = data.readInt(); - - readBuilding(data); - - if(mined != -1){ - mineTile = world.tile(mined); - } - } - public final UnitState build = new UnitState(){ - public void entered() { + + public void entered(){ if(!(target instanceof BuildEntity)){ target = null; } } - public void update() { - BuildEntity entity = (BuildEntity)target; + public void update(){ + BuildEntity entity = (BuildEntity) target; TileEntity core = getClosestCore(); if(entity == null){ @@ -247,7 +77,7 @@ public class Drone extends FlyingUnit implements BuilderTrait { //if it's missing requirements, try and mine them for(ItemStack stack : entity.recipe.requirements){ - if(!core.items.hasItem(stack.item, stack.amount) && toMine.contains(stack.item)){ + if(!core.items.has(stack.item, stack.amount) && toMine.contains(stack.item)){ targetItem = stack.item; getPlaceQueue().clear(); setState(mine); @@ -263,17 +93,18 @@ public class Drone extends FlyingUnit implements BuilderTrait { }, repair = new UnitState(){ - public void entered() { + + public void entered(){ target = null; } - public void update() { - if(target != null && (((TileEntity)target).health >= ((TileEntity)target).tile.block().health + public void update(){ + if(target != null && (((TileEntity) target).health >= ((TileEntity) target).tile.block().health || target.distanceTo(Drone.this) > discoverRange)){ target = null; } - if (target == null) { + if(target == null){ retarget(() -> { target = Units.findAllyTile(team, x, y, discoverRange, tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health); @@ -291,17 +122,18 @@ public class Drone extends FlyingUnit implements BuilderTrait { } } }, - mine = new UnitState() { - public void entered() { + + mine = new UnitState(){ + public void entered(){ target = null; } - public void update() { + public void update(){ TileEntity entity = getClosestCore(); if(entity == null) return; - if(targetItem == null) { + if(targetItem == null){ findItem(); } @@ -334,31 +166,31 @@ public class Drone extends FlyingUnit implements BuilderTrait { target = world.indexer().findClosestOre(x, y, targetItem); }); - if(target instanceof Tile) { - moveTo(type.range/1.5f); + if(target instanceof Tile){ + moveTo(type.range / 1.5f); - if (distanceTo(target) < type.range && mineTile != target) { - setMineTile((Tile)target); + if(distanceTo(target) < type.range && mineTile != target){ + setMineTile((Tile) target); } - if(((Tile)target).block() != Blocks.air){ + if(((Tile) target).block() != Blocks.air){ setState(drop); } } } } - public void exited() { + public void exited(){ setMineTile(null); } }, - pickup = new UnitState() { - public void entered() { + pickup = new UnitState(){ + public void entered(){ target = null; } - public void update() { - ItemDrop item = (ItemDrop)target; + public void update(){ + ItemDrop item = (ItemDrop) target; if(inventory.isFull() || !inventory.canAcceptItem(item.getItem(), 1)){ setState(drop); @@ -379,12 +211,12 @@ public class Drone extends FlyingUnit implements BuilderTrait { moveTo(0f); } }, - drop = new UnitState() { - public void entered() { + drop = new UnitState(){ + public void entered(){ target = null; } - public void update() { + public void update(){ if(inventory.isEmpty()){ setState(mine); return; @@ -394,10 +226,10 @@ public class Drone extends FlyingUnit implements BuilderTrait { if(target == null) return; - TileEntity tile = (TileEntity)target; + TileEntity tile = (TileEntity) target; if(distanceTo(target) < type.range){ - if(tile.tile.block().acceptStack(inventory.getItem().item, inventory.getItem().amount, tile.tile, Drone.this) == inventory.getItem().amount) { + if(tile.tile.block().acceptStack(inventory.getItem().item, inventory.getItem().amount, tile.tile, Drone.this) == inventory.getItem().amount){ CallEntity.transferItemTo(inventory.getItem().item, inventory.getItem().amount, x, y, tile.tile); inventory.clearItem(); } @@ -405,21 +237,21 @@ public class Drone extends FlyingUnit implements BuilderTrait { setState(repair); } - circle(type.range/1.8f); + circle(type.range / 1.8f); } }, - retreat = new UnitState() { - public void entered() { + retreat = new UnitState(){ + public void entered(){ target = null; } - public void update() { + public void update(){ if(health >= health){ state.set(attack); }else if(!targetHasFlag(BlockFlag.repair)){ - if(timer.get(timerTarget, 20)) { + if(timer.get(timerTarget, 20)){ Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)); - if (target != null) Drone.this.target = target.entity; + if(target != null) Drone.this.target = target.entity; } }else{ circle(40f); @@ -427,4 +259,199 @@ public class Drone extends FlyingUnit implements BuilderTrait { } }; + { + initEvents(); + } + + /** + * Initialize placement event notifier system. + * Static initialization is to be avoided, thus, this is done lazily. + */ + private static void initEvents(){ + if(initialized) return; + + toMine = ObjectSet.with(Items.lead, Items.tungsten); + + Events.on(BlockBuildEvent.class, (team, tile) -> { + EntityGroup group = unitGroups[team.ordinal()]; + + if(!(tile.entity instanceof BuildEntity)) return; + BuildEntity entity = tile.entity(); + + for(BaseUnit unit : group.all()){ + if(unit instanceof Drone){ + ((Drone) unit).notifyPlaced(entity); + } + } + }); + + initialized = true; + } + + private void notifyPlaced(BuildEntity entity){ + float timeToBuild = entity.recipe.cost; + float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0); + + if(dist / type.maxVelocity < timeToBuild * 0.9f){ + //CallEntity.onDroneBeginBuild(this, entity.tile, entity.recipe); + target = entity; + setState(build); + } + } + + @Override + public float getBuildPower(Tile tile){ + return type.buildPower; + } + + @Override + public float getMinePower(){ + return type.minePower; + } + + @Override + public Queue getPlaceQueue(){ + return placeQueue; + } + + @Override + public Tile getMineTile(){ + return mineTile; + } + + @Override + public void setMineTile(Tile tile){ + mineTile = tile; + } + + @Override + public void update(){ + super.update(); + + if(Net.client() && state.is(repair) && target instanceof TileEntity){ + TileEntity entity = (TileEntity) target; + entity.health += type.healSpeed * Timers.delta(); + entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health); + } + + x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f); + y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f); + + updateBuilding(this); + } + + @Override + protected void updateRotation(){ + if(target != null && (state.is(repair) || state.is(mine))){ + rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f); + }else{ + rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f); + } + + if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){ + rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f); + } + } + + @Override + public void behavior(){ + if(health <= health * type.retreatPercent && + Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){ + setState(retreat); + } + } + + @Override + public UnitState getStartState(){ + return repair; + } + + @Override + public void drawOver(){ + trail.draw(Palette.lightTrail, 3f); + + TargetTrait entity = target; + + if(entity instanceof TileEntity && state.is(repair)){ + float len = 5f; + Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f)); + Shapes.laser("beam", "beam-end", + x + Angles.trnsx(rotation, len), + y + Angles.trnsy(rotation, len), + entity.getX(), entity.getY()); + Draw.color(); + } + + drawBuilding(this); + } + + @Override + public float drawSize(){ + return isBuilding() ? placeDistance * 2f : 30f; + } + + @Override + public float getAmmoFraction(){ + return inventory.getItem().amount / (float) type.itemCapacity; + } + + protected void findItem(){ + TileEntity entity = getClosestCore(); + if(entity == null){ + return; + } + targetItem = Mathf.findMin(toMine, (a, b) -> -Integer.compare(entity.items.get(a), entity.items.get(b))); + } + + protected boolean findItemDrop(){ + TileEntity core = getClosestCore(); + + if(core == null) return false; + + //find nearby dropped items to pick up if applicable + ItemDrop drop = EntityPhysics.getClosest(itemGroup, x, y, 60f, + item -> core.tile.block().acceptStack(item.getItem(), item.getAmount(), core.tile, Drone.this) == item.getAmount() && + inventory.canAcceptItem(item.getItem(), 1)); + if(drop != null){ + setState(pickup); + target = drop; + return true; + } + return false; + } + + @Override + public boolean canCreateBlocks(){ + return false; + } + + @Override + public void write(DataOutput data) throws IOException{ + super.write(data); + data.writeInt(mineTile == null ? -1 : mineTile.packedPosition()); + data.writeInt(state.is(repair) && target instanceof TileEntity ? ((TileEntity)target).tile.packedPosition() : -1); + writeBuilding(data); + } + + @Override + public void read(DataInput data, long time) throws IOException{ + super.read(data, time); + int mined = data.readInt(); + int repairing = data.readInt(); + + readBuilding(data); + + if(mined != -1){ + mineTile = world.tile(mined); + } + + if(repairing != -1){ + Tile tile = world.tile(repairing); + target = tile.entity; + state.set(repair); + }else{ + state.set(retreat); + } + } + } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Fabricator.java b/core/src/io/anuke/mindustry/entities/units/types/Fabricator.java index 89dcea9646..90119c8550 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Fabricator.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Fabricator.java @@ -1,5 +1,5 @@ package io.anuke.mindustry.entities.units.types; -public class Fabricator extends Drone { +public class Fabricator extends Drone{ } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Monsoon.java b/core/src/io/anuke/mindustry/entities/units/types/Monsoon.java index 09db7fc53a..b87e0d2f81 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Monsoon.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Monsoon.java @@ -2,6 +2,6 @@ package io.anuke.mindustry.entities.units.types; import io.anuke.mindustry.entities.units.FlyingUnit; -public class Monsoon extends FlyingUnit { +public class Monsoon extends FlyingUnit{ } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Scout.java b/core/src/io/anuke/mindustry/entities/units/types/Scout.java index 765dbfbb12..bdfdbe4f89 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Scout.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Scout.java @@ -2,6 +2,6 @@ package io.anuke.mindustry.entities.units.types; import io.anuke.mindustry.entities.units.GroundUnit; -public class Scout extends GroundUnit { +public class Scout extends GroundUnit{ } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java index 370446b148..cf02014794 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java @@ -2,6 +2,6 @@ package io.anuke.mindustry.entities.units.types; import io.anuke.mindustry.entities.units.FlyingUnit; -public class Vtol extends FlyingUnit { +public class Vtol extends FlyingUnit{ } diff --git a/core/src/io/anuke/mindustry/game/Content.java b/core/src/io/anuke/mindustry/game/Content.java index 542f78f97c..accf8d0947 100644 --- a/core/src/io/anuke/mindustry/game/Content.java +++ b/core/src/io/anuke/mindustry/game/Content.java @@ -2,20 +2,32 @@ package io.anuke.mindustry.game; import com.badlogic.gdx.utils.Array; -/**Base interface for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}.*/ -public interface Content { +/** + * Base interface for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. + */ +public interface Content{ - /**Returns the type name of this piece of content. - * This should return the same value for all instances of this content type.*/ + /** + * Returns the type name of this piece of content. + * This should return the same value for all instances of this content type. + */ String getContentTypeName(); - /**Returns a list of all instances of this content.*/ + /** + * Returns a list of all instances of this content. + */ Array getAll(); - /**Called after all content is created. Do not use to load regions or texture data!*/ - default void init(){} + /** + * Called after all content is created. Do not use to load regions or texture data! + */ + default void init(){ + } - /**Called after all content is created, only on non-headless versions. - * Use for loading regions or other image data.*/ - default void load(){} + /** + * Called after all content is created, only on non-headless versions. + * Use for loading regions or other image data. + */ + default void load(){ + } } diff --git a/core/src/io/anuke/mindustry/game/ContentDatabase.java b/core/src/io/anuke/mindustry/game/ContentDatabase.java index d01a7e97cc..ed658e111f 100644 --- a/core/src/io/anuke/mindustry/game/ContentDatabase.java +++ b/core/src/io/anuke/mindustry/game/ContentDatabase.java @@ -8,13 +8,19 @@ import io.anuke.mindustry.game.EventType.UnlockEvent; import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Settings; -public class ContentDatabase { - /**Maps unlockable type names to a set of unlocked content.*/ +public class ContentDatabase{ + /** + * Maps unlockable type names to a set of unlocked content. + */ private ObjectMap> unlocked = new ObjectMap<>(); - /**Whether unlockables have changed since the last save.*/ + /** + * Whether unlockables have changed since the last save. + */ private boolean dirty; - /**Returns whether or not this piece of content is unlocked yet.*/ + /** + * Returns whether or not this piece of content is unlocked yet. + */ public boolean isUnlocked(UnlockableContent content){ if(!unlocked.containsKey(content.getContentTypeName())){ unlocked.put(content.getContentTypeName(), new ObjectSet<>()); @@ -25,10 +31,13 @@ public class ContentDatabase { return set.contains(content.getContentName()); } - /**Makes this piece of content 'unlocked', if possible. + /** + * Makes this piece of content 'unlocked', if possible. * If this piece of content is already unlocked or cannot be unlocked due to dependencies, nothing changes. * Results are not saved until you call {@link #save()}. - * @return whether or not this content was newly unlocked.*/ + * + * @return whether or not this content was newly unlocked. + */ public boolean unlockContent(UnlockableContent content){ if(!content.canBeUnlocked()) return false; @@ -48,12 +57,16 @@ public class ContentDatabase { return ret; } - /**Returns whether unlockables have changed since the last save.*/ + /** + * Returns whether unlockables have changed since the last save. + */ public boolean isDirty(){ return dirty; } - /**Clears all unlocked content.*/ + /** + * Clears all unlocked content. + */ public void reset(){ unlocked.clear(); dirty = true; diff --git a/core/src/io/anuke/mindustry/game/Difficulty.java b/core/src/io/anuke/mindustry/game/Difficulty.java index 4f7091a58f..7c86e5685e 100644 --- a/core/src/io/anuke/mindustry/game/Difficulty.java +++ b/core/src/io/anuke/mindustry/game/Difficulty.java @@ -2,7 +2,7 @@ package io.anuke.mindustry.game; import io.anuke.ucore.util.Bundles; -public enum Difficulty { +public enum Difficulty{ easy(4f, 2f, 1f), normal(2f, 1f, 1f), hard(1.5f, 0.5f, 0.75f), @@ -10,13 +10,19 @@ public enum Difficulty { //purge removed due to new wave system /*purge(0.25f, 0.01f, 0.25f)*/; - /**The scaling of how many waves it takes for one more enemy of a type to appear. + /** + * The scaling of how many waves it takes for one more enemy of a type to appear. * For example: with enemeyScaling = 2 and the default scaling being 2, it would take 4 waves for - * an enemy spawn to go from 1->2 enemies.*/ + * an enemy spawn to go from 1->2 enemies. + */ public final float enemyScaling; - /**Multiplier of the time between waves.*/ + /** + * Multiplier of the time between waves. + */ public final float timeScaling; - /**Scaling of max time between waves. Default time is 4 minutes.*/ + /** + * Scaling of max time between waves. Default time is 4 minutes. + */ public final float maxTimeScaling; private String value; @@ -28,7 +34,7 @@ public enum Difficulty { } @Override - public String toString() { + public String toString(){ if(value == null){ value = Bundles.get("setting.difficulty." + name()); } diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index 9aecf1a473..ec880f3be9 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -4,7 +4,7 @@ import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.function.Event; -public class EventType { +public class EventType{ public interface PlayEvent extends Event{ void handle(); @@ -22,19 +22,25 @@ public class EventType { void handle(); } - /**This event is called from the logic thread. - * DO NOT INITIALIZE GRAPHICS HERE.*/ + /** + * This event is called from the logic thread. + * DO NOT INITIALIZE GRAPHICS HERE. + */ public interface WorldLoadEvent extends Event{ void handle(); } - /**Called after the WorldLoadEvent is, and all logic has been loaded. - * It is safe to intialize graphics here.*/ + /** + * Called after the WorldLoadEvent is, and all logic has been loaded. + * It is safe to intialize graphics here. + */ public interface WorldLoadGraphicsEvent extends Event{ void handle(); } - /**Called from the logic thread. Do not access graphics here!*/ + /** + * Called from the logic thread. Do not access graphics here! + */ public interface TileChangeEvent extends Event{ void handle(Tile tile); } diff --git a/core/src/io/anuke/mindustry/game/GameMode.java b/core/src/io/anuke/mindustry/game/GameMode.java index cbc7f7349d..fcf9e8c09a 100644 --- a/core/src/io/anuke/mindustry/game/GameMode.java +++ b/core/src/io/anuke/mindustry/game/GameMode.java @@ -3,8 +3,8 @@ package io.anuke.mindustry.game; import io.anuke.ucore.util.Bundles; public enum GameMode{ - waves, - //disabled for technical reasons + waves, + //disabled for technical reasons /*sandbox{ { infiniteResources = true; @@ -16,16 +16,16 @@ public enum GameMode{ disableWaveTimer = true; } }; - public boolean infiniteResources; - public boolean disableWaveTimer; + public boolean infiniteResources; + public boolean disableWaveTimer; - public String description(){ - return Bundles.get("mode."+name()+".description"); - } + public String description(){ + return Bundles.get("mode." + name() + ".description"); + } - @Override - public String toString(){ - return Bundles.get("mode."+name()+".name"); - } + @Override + public String toString(){ + return Bundles.get("mode." + name() + ".name"); + } } diff --git a/core/src/io/anuke/mindustry/game/SpawnGroup.java b/core/src/io/anuke/mindustry/game/SpawnGroup.java index 6c91faa1ac..4d8fe850be 100644 --- a/core/src/io/anuke/mindustry/game/SpawnGroup.java +++ b/core/src/io/anuke/mindustry/game/SpawnGroup.java @@ -8,84 +8,118 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.StatusEffect; import io.anuke.mindustry.type.Weapon; -/**A spawn group defines spawn information for a specific type of unit, with optional extra information like +/** + * A spawn group defines spawn information for a specific type of unit, with optional extra information like * weapon equipped, ammo used, and status effects. - * Each spawn group can have multiple sub-groups spawned in different areas of the map.*/ -public class SpawnGroup { - /**The unit type spawned*/ - public final UnitType type; - /**When this spawn should end*/ - protected int end = Integer.MAX_VALUE; - /**When this spawn should start*/ - protected int begin; - /**The spacing, in waves, of spawns. For example, 2 = spawns every other wave*/ - protected int spacing = 1; - /**Maximum amount of units that spawn*/ - protected int max = 60; - /**How many waves need to pass before the amount of units spawned increases by 1*/ - protected float unitScaling = 9999f; - /**How many waves need to pass before the amount of instances of this group increases by 1*/ - protected float groupScaling = 9999f; - /**Amount of enemies spawned initially, with no scaling*/ - protected int unitAmount = 1; - /**Amount of enemies spawned initially, with no scaling*/ - protected int groupAmount = 1; - /**Weapon used by the spawned unit. Null to disable. Only applicable to ground units.*/ - protected Weapon weapon; - /**Status effect applied to the spawned unit. Null to disable.*/ - protected StatusEffect effect; - /**Items this unit spawns with. Null to disable.*/ - protected ItemStack items; - /**Ammo type this unit spawns with. Null to use the first available ammo.*/ - protected Item ammoItem; - - public SpawnGroup(UnitType type){ - this.type = type; - } + * Each spawn group can have multiple sub-groups spawned in different areas of the map. + */ +public class SpawnGroup{ + /** + * The unit type spawned + */ + public final UnitType type; + /** + * When this spawn should end + */ + protected int end = Integer.MAX_VALUE; + /** + * When this spawn should start + */ + protected int begin; + /** + * The spacing, in waves, of spawns. For example, 2 = spawns every other wave + */ + protected int spacing = 1; + /** + * Maximum amount of units that spawn + */ + protected int max = 60; + /** + * How many waves need to pass before the amount of units spawned increases by 1 + */ + protected float unitScaling = 9999f; + /** + * How many waves need to pass before the amount of instances of this group increases by 1 + */ + protected float groupScaling = 9999f; + /** + * Amount of enemies spawned initially, with no scaling + */ + protected int unitAmount = 1; + /** + * Amount of enemies spawned initially, with no scaling + */ + protected int groupAmount = 1; + /** + * Weapon used by the spawned unit. Null to disable. Only applicable to ground units. + */ + protected Weapon weapon; + /** + * Status effect applied to the spawned unit. Null to disable. + */ + protected StatusEffect effect; + /** + * Items this unit spawns with. Null to disable. + */ + protected ItemStack items; + /** + * Ammo type this unit spawns with. Null to use the first available ammo. + */ + protected Item ammoItem; - /**Returns the amount of units spawned on a specific wave.*/ - public int getUnitsSpawned(int wave){ - if(wave < begin || wave > end || (wave - begin) % spacing != 0){ - return 0; - } - float scaling = this.unitScaling; - - return Math.min(unitAmount-1 + Math.max((int)((wave / spacing) / scaling), 1), max); - } + public SpawnGroup(UnitType type){ + this.type = type; + } - /**Returns the amount of different unit groups at a specific wave.*/ - public int getGroupsSpawned(int wave){ - if(wave < begin || wave > end || (wave - begin) % spacing != 0){ - return 0; - } - float scaling = this.groupScaling; + /** + * Returns the amount of units spawned on a specific wave. + */ + public int getUnitsSpawned(int wave){ + if(wave < begin || wave > end || (wave - begin) % spacing != 0){ + return 0; + } + float scaling = this.unitScaling; - return Math.min(groupAmount-1 + Math.max((int)((wave / spacing) / groupScaling), 1), max); - } + return Math.min(unitAmount - 1 + Math.max((int) ((wave / spacing) / scaling), 1), max); + } - /**Creates a unit, and assigns correct values based on this group's data. - * This method does not add() the unit.*/ - public BaseUnit createUnit(Team team){ - BaseUnit unit = type.create(team); + /** + * Returns the amount of different unit groups at a specific wave. + */ + public int getGroupsSpawned(int wave){ + if(wave < begin || wave > end || (wave - begin) % spacing != 0){ + return 0; + } + float scaling = this.groupScaling; - if(unit instanceof GroundUnit && weapon != null){ - ((GroundUnit) unit).setWeapon(weapon); - } + return Math.min(groupAmount - 1 + Math.max((int) ((wave / spacing) / groupScaling), 1), max); + } - if(effect != null){ - unit.applyEffect(effect, 10000f); - } + /** + * Creates a unit, and assigns correct values based on this group's data. + * This method does not add() the unit. + */ + public BaseUnit createUnit(Team team){ + BaseUnit unit = type.create(team); - if(items != null){ - unit.inventory.addItem(items.item, items.amount); - } + if(unit instanceof GroundUnit && weapon != null){ + ((GroundUnit) unit).setWeapon(weapon); + } - if(ammoItem != null){ - unit.inventory.addAmmo(unit.getWeapon().getAmmoType(ammoItem)); - }else{ - unit.inventory.addAmmo(unit.getWeapon().getAmmoType(unit.getWeapon().getAcceptedItems().iterator().next())); - } + if(effect != null){ + unit.applyEffect(effect, 10000f); + } - return unit; - } + if(items != null){ + unit.inventory.addItem(items.item, items.amount); + } + + if(ammoItem != null){ + unit.inventory.addAmmo(unit.getWeapon().getAmmoType(ammoItem)); + }else{ + unit.inventory.addAmmo(unit.getWeapon().getAmmoType(unit.getWeapon().getAcceptedItems().iterator().next())); + } + + return unit; + } } diff --git a/core/src/io/anuke/mindustry/game/Team.java b/core/src/io/anuke/mindustry/game/Team.java index 0d97c39285..7fce5dc6fb 100644 --- a/core/src/io/anuke/mindustry/game/Team.java +++ b/core/src/io/anuke/mindustry/game/Team.java @@ -2,7 +2,7 @@ package io.anuke.mindustry.game; import com.badlogic.gdx.graphics.Color; -public enum Team { +public enum Team{ none(Color.DARK_GRAY), blue(Color.ROYAL), red(Color.valueOf("e84737")), @@ -10,11 +10,10 @@ public enum Team { purple(Color.valueOf("ba5bd9")), orange(Color.valueOf("e8c66a")); + public final static Team[] all = values(); public final Color color; public final int intColor; - public final static Team[] all = values(); - Team(Color color){ this.color = color; intColor = Color.rgba8888(color); diff --git a/core/src/io/anuke/mindustry/game/TeamInfo.java b/core/src/io/anuke/mindustry/game/TeamInfo.java index 33ea3b37c7..8559fde11d 100644 --- a/core/src/io/anuke/mindustry/game/TeamInfo.java +++ b/core/src/io/anuke/mindustry/game/TeamInfo.java @@ -6,8 +6,10 @@ import io.anuke.mindustry.world.Tile; import io.anuke.ucore.util.ThreadArray; import io.anuke.ucore.util.ThreadSet; -/**Class for various team-based utilities.*/ -public class TeamInfo { +/** + * Class for various team-based utilities. + */ +public class TeamInfo{ private ObjectMap map = new ObjectMap<>(); private ThreadSet allies = new ThreadSet<>(), enemies = new ThreadSet<>(); @@ -18,30 +20,37 @@ public class TeamInfo { private int allyBits = 0; private int enemyBits = 0; - /**Returns all teams on a side.*/ - public ObjectSet getTeams(boolean ally) { + /** + * Returns all teams on a side. + */ + public ObjectSet getTeams(boolean ally){ return ally ? allyData : enemyData; } - /**Returns all team data.*/ - public ObjectSet getTeams() { + /** + * Returns all team data. + */ + public ObjectSet getTeams(){ return allTeamData; } - /**Register a team. + /** + * Register a team. + * * @param team The team type enum. * @param ally Whether this team is an ally with the player or an enemy with the player. - * In PvP situations with dedicated servers, the sides can be arbitrary.*/ + * In PvP situations with dedicated servers, the sides can be arbitrary. + */ public void add(Team team, boolean ally){ if(has(team)) throw new RuntimeException("Can't define team information twice!"); TeamData data = new TeamData(team, ally); - if(ally) { + if(ally){ allies.add(team); allyData.add(data); allyBits |= (1 << team.ordinal()); - }else { + }else{ enemies.add(team); enemyData.add(data); enemyBits |= (1 << team.ordinal()); @@ -53,20 +62,26 @@ public class TeamInfo { map.put(team, data); } - /**Returns team data by type. Call {@link #has(Team)} first to make sure it's active!*/ + /** + * Returns team data by type. Call {@link #has(Team)} first to make sure it's active! + */ public TeamData get(Team team){ if(!has(team)) throw new RuntimeException("This team is not active! Check has() before calling get()."); return map.get(team); } - /**Returns whether the specified team is active, e.g. whether it is participating in the game.*/ + /** + * Returns whether the specified team is active, e.g. whether it is participating in the game. + */ public boolean has(Team team){ return map.containsKey(team); } - /**Returns a set of all teams that are enemies of this team. - * For teams not active, an empty set is returned.*/ - public ObjectSet enemiesOf(Team team) { + /** + * Returns a set of all teams that are enemies of this team. + * For teams not active, an empty set is returned. + */ + public ObjectSet enemiesOf(Team team){ boolean ally = allies.contains(team); boolean enemy = enemies.contains(team); @@ -76,9 +91,11 @@ public class TeamInfo { return ally ? enemies : allies; } - /**Returns a set of all teams that are allies of this team. - * For teams not active, an empty set is returned.*/ - public ObjectSet alliesOf(Team team) { + /** + * Returns a set of all teams that are allies of this team. + * For teams not active, an empty set is returned. + */ + public ObjectSet alliesOf(Team team){ boolean ally = allies.contains(team); boolean enemy = enemies.contains(team); @@ -88,9 +105,11 @@ public class TeamInfo { return !ally ? enemies : allies; } - /**Returns a set of all teams that are enemies of this team. - * For teams not active, an empty set is returned.*/ - public ObjectSet enemyDataOf(Team team) { + /** + * Returns a set of all teams that are enemies of this team. + * For teams not active, an empty set is returned. + */ + public ObjectSet enemyDataOf(Team team){ boolean ally = allies.contains(team); boolean enemy = enemies.contains(team); @@ -100,7 +119,9 @@ public class TeamInfo { return ally ? enemyData : allyData; } - /**Returns whether or not these two teams are enemies.*/ + /** + * Returns whether or not these two teams are enemies. + */ public boolean areEnemies(Team team, Team other){ if(team == other) return false; //fast fail to be more efficient boolean ally = (allyBits & (1 << team.ordinal())) != 0; @@ -108,12 +129,12 @@ public class TeamInfo { return (ally == enemy) || !ally; //if it's not in the game, target everything. } - public class TeamData { + public class TeamData{ public final ThreadArray cores = new ThreadArray<>(); public final Team team; public final boolean ally; - public TeamData(Team team, boolean ally) { + public TeamData(Team team, boolean ally){ this.team = team; this.ally = ally; } diff --git a/core/src/io/anuke/mindustry/game/UnlockableContent.java b/core/src/io/anuke/mindustry/game/UnlockableContent.java index b42ed1c645..6c04c7ad06 100644 --- a/core/src/io/anuke/mindustry/game/UnlockableContent.java +++ b/core/src/io/anuke/mindustry/game/UnlockableContent.java @@ -5,37 +5,54 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.control; -/**Base interface for an unlockable content type.*/ +/** + * Base interface for an unlockable content type. + */ public interface UnlockableContent extends Content{ - /**Returns the unqiue name of this piece of content. + /** + * Returns the unqiue name of this piece of content. * The name only needs to be unique for all content of this type. * Do not use IDs for names! Make sure this string stays constant with each update unless removed. - * (e.g. having a recipe and a block, both with name "wall" is fine, as they are different types).*/ + * (e.g. having a recipe and a block, both with name "wall" is fine, as they are different types). + */ String getContentName(); - /**Returns the localized name of this content.*/ + /** + * Returns the localized name of this content. + */ String localizedName(); TextureRegion getContentIcon(); - /**This should show all necessary info about this content in the specified table.*/ + /** + * This should show all necessary info about this content in the specified table. + */ void displayInfo(Table table); - /**Called when this content is unlocked. Use this to unlock other related content.*/ - default void onUnlock(){} + /** + * Called when this content is unlocked. Use this to unlock other related content. + */ + default void onUnlock(){ + } - /**Whether this content is always hidden in the content info dialog.*/ + /** + * Whether this content is always hidden in the content info dialog. + */ default boolean isHidden(){ return false; } - /**Lists the content that must be unlocked in order for this specific content to become unlocked. May return null.*/ + /** + * Lists the content that must be unlocked in order for this specific content to become unlocked. May return null. + */ default UnlockableContent[] getDependencies(){ return null; } - /**Returns whether dependencies are satisfied for unlocking this content.*/ + /** + * Returns whether dependencies are satisfied for unlocking this content. + */ default boolean canBeUnlocked(){ UnlockableContent[] depend = getDependencies(); if(depend == null){ diff --git a/core/src/io/anuke/mindustry/game/WaveCreator.java b/core/src/io/anuke/mindustry/game/WaveCreator.java index c1d2adb8e2..a5e5e25340 100644 --- a/core/src/io/anuke/mindustry/game/WaveCreator.java +++ b/core/src/io/anuke/mindustry/game/WaveCreator.java @@ -8,183 +8,183 @@ import io.anuke.mindustry.content.Weapons; import io.anuke.mindustry.type.ItemStack; public class WaveCreator{ - - public static Array getSpawns(){ - return Array.with( - new SpawnGroup(UnitTypes.scout){{ - end = 8; - unitScaling = 2; - }}, - new SpawnGroup(UnitTypes.vtol){{ - begin = 12; - end = 14; - }}, + public static Array getSpawns(){ + return Array.with( + new SpawnGroup(UnitTypes.scout){{ + end = 8; + unitScaling = 2; + }}, - new SpawnGroup(UnitTypes.scout){{ - begin = 11; - unitScaling = 2; - spacing = 2; - max = 4; - }}, + new SpawnGroup(UnitTypes.vtol){{ + begin = 12; + end = 14; + }}, - new SpawnGroup(UnitTypes.titan){{ - begin = 9; - spacing = 3; - unitScaling = 2; + new SpawnGroup(UnitTypes.scout){{ + begin = 11; + unitScaling = 2; + spacing = 2; + max = 4; + }}, - end = 30; - }}, + new SpawnGroup(UnitTypes.titan){{ + begin = 9; + spacing = 3; + unitScaling = 2; - new SpawnGroup(UnitTypes.scout){{ - begin = 10; - unitScaling = 2; - unitAmount = 1; - spacing = 2; - ammoItem = Items.tungsten; - end = 30; - }}, + end = 30; + }}, - new SpawnGroup(UnitTypes.titan){{ - begin = 28; - spacing = 3; - unitScaling = 2; - weapon = Weapons.flamethrower; - end = 40; - }}, + new SpawnGroup(UnitTypes.scout){{ + begin = 10; + unitScaling = 2; + unitAmount = 1; + spacing = 2; + ammoItem = Items.tungsten; + end = 30; + }}, - new SpawnGroup(UnitTypes.titan){{ - begin = 45; - spacing = 3; - unitScaling = 2; - weapon = Weapons.flamethrower; - effect = StatusEffects.overdrive; - }}, + new SpawnGroup(UnitTypes.titan){{ + begin = 28; + spacing = 3; + unitScaling = 2; + weapon = Weapons.flamethrower; + end = 40; + }}, - new SpawnGroup(UnitTypes.titan){{ - begin = 120; - spacing = 2; - unitScaling = 3; - unitAmount = 5; - weapon = Weapons.flakgun; - effect = StatusEffects.overdrive; - }}, + new SpawnGroup(UnitTypes.titan){{ + begin = 45; + spacing = 3; + unitScaling = 2; + weapon = Weapons.flamethrower; + effect = StatusEffects.overdrive; + }}, - new SpawnGroup(UnitTypes.vtol){{ - begin = 16; - unitScaling = 2; - spacing = 2; + new SpawnGroup(UnitTypes.titan){{ + begin = 120; + spacing = 2; + unitScaling = 3; + unitAmount = 5; + weapon = Weapons.flakgun; + effect = StatusEffects.overdrive; + }}, - end = 39; - max = 7; - }}, + new SpawnGroup(UnitTypes.vtol){{ + begin = 16; + unitScaling = 2; + spacing = 2; - new SpawnGroup(UnitTypes.scout){{ - begin = 82; - spacing = 3; - unitAmount = 4; - groupAmount = 2; - unitScaling = 3; - effect = StatusEffects.overdrive; - ammoItem = Items.silicon; - }}, + end = 39; + max = 7; + }}, - new SpawnGroup(UnitTypes.scout){{ - begin = 41; - spacing = 5; - unitAmount = 1; - unitScaling = 3; - effect = StatusEffects.shielded; - ammoItem = Items.thorium; - max = 10; - }}, + new SpawnGroup(UnitTypes.scout){{ + begin = 82; + spacing = 3; + unitAmount = 4; + groupAmount = 2; + unitScaling = 3; + effect = StatusEffects.overdrive; + ammoItem = Items.silicon; + }}, - new SpawnGroup(UnitTypes.scout){{ - begin = 35; - spacing = 3; - unitAmount = 4; - groupAmount = 2; - effect = StatusEffects.overdrive; - items = new ItemStack(Items.blastCompound, 60); - end = 60; - }}, + new SpawnGroup(UnitTypes.scout){{ + begin = 41; + spacing = 5; + unitAmount = 1; + unitScaling = 3; + effect = StatusEffects.shielded; + ammoItem = Items.thorium; + max = 10; + }}, - new SpawnGroup(UnitTypes.scout){{ - begin = 42; - spacing = 3; - unitAmount = 4; - groupAmount = 2; - effect = StatusEffects.overdrive; - items = new ItemStack(Items.pyratite, 100); - end = 130; - }}, + new SpawnGroup(UnitTypes.scout){{ + begin = 35; + spacing = 3; + unitAmount = 4; + groupAmount = 2; + effect = StatusEffects.overdrive; + items = new ItemStack(Items.blastCompound, 60); + end = 60; + }}, - new SpawnGroup(UnitTypes.monsoon){{ - begin = 40; - ammoItem = Items.blastCompound; - unitAmount = 2; - spacing = 2; - unitScaling = 3; - max = 8; - }}, + new SpawnGroup(UnitTypes.scout){{ + begin = 42; + spacing = 3; + unitAmount = 4; + groupAmount = 2; + effect = StatusEffects.overdrive; + items = new ItemStack(Items.pyratite, 100); + end = 130; + }}, - new SpawnGroup(UnitTypes.vtol){{ - begin = 50; - unitAmount = 4; - unitScaling = 3; - spacing = 5; - groupAmount = 2; - effect = StatusEffects.overdrive; - max = 8; - }}, + new SpawnGroup(UnitTypes.monsoon){{ + begin = 40; + ammoItem = Items.blastCompound; + unitAmount = 2; + spacing = 2; + unitScaling = 3; + max = 8; + }}, - new SpawnGroup(UnitTypes.monsoon){{ - begin = 53; - ammoItem = Items.pyratite; - unitAmount = 2; - unitScaling = 3; - spacing = 4; - max = 8; - end = 74; - }}, + new SpawnGroup(UnitTypes.vtol){{ + begin = 50; + unitAmount = 4; + unitScaling = 3; + spacing = 5; + groupAmount = 2; + effect = StatusEffects.overdrive; + max = 8; + }}, - new SpawnGroup(UnitTypes.monsoon){{ - begin = 53; - ammoItem = Items.coal; - unitAmount = 2; - unitScaling = 3; - spacing = 4; - max = 8; - end = 74; - }} - ); - } + new SpawnGroup(UnitTypes.monsoon){{ + begin = 53; + ammoItem = Items.pyratite; + unitAmount = 2; + unitScaling = 3; + spacing = 4; + max = 8; + end = 74; + }}, - public static void testWaves(int from, int to){ - Array spawns = getSpawns(); - for(int i = from; i <= to; i ++){ - System.out.print(i+": "); - int total = 0; - for(SpawnGroup spawn : spawns){ - int a = spawn.getUnitsSpawned(i) * spawn.getGroupsSpawned(i); - total += a; - - if(a > 0){ - System.out.print(a+"x" + spawn.type.name); + new SpawnGroup(UnitTypes.monsoon){{ + begin = 53; + ammoItem = Items.coal; + unitAmount = 2; + unitScaling = 3; + spacing = 4; + max = 8; + end = 74; + }} + ); + } - if(spawn.weapon != null){ - System.out.print(":" + spawn.weapon.name); - } + public static void testWaves(int from, int to){ + Array spawns = getSpawns(); + for(int i = from; i <= to; i++){ + System.out.print(i + ": "); + int total = 0; + for(SpawnGroup spawn : spawns){ + int a = spawn.getUnitsSpawned(i) * spawn.getGroupsSpawned(i); + total += a; - if(spawn.ammoItem != null){ - System.out.print(":" + spawn.ammoItem.name); - } + if(a > 0){ + System.out.print(a + "x" + spawn.type.name); - System.out.print(" "); - } - } - System.out.print(" (" + total + ")"); - System.out.println(); - } - } + if(spawn.weapon != null){ + System.out.print(":" + spawn.weapon.name); + } + + if(spawn.ammoItem != null){ + System.out.print(":" + spawn.ammoItem.name); + } + + System.out.print(" "); + } + } + System.out.print(" (" + total + ")"); + System.out.println(); + } + } } diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 86e01d8300..0f6317a7e0 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -15,203 +15,207 @@ import static io.anuke.mindustry.Vars.*; import static io.anuke.ucore.core.Core.camera; public class BlockRenderer{ - private final static int initialRequests = 32*32; + private final static int initialRequests = 32 * 32; - private FloorRenderer floorRenderer; - - private Array requests = new Array<>(initialRequests); - private Layer lastLayer; - private int requestidx = 0; - private int iterateidx = 0; + private FloorRenderer floorRenderer; - public BlockRenderer(){ - floorRenderer = new FloorRenderer(); + private Array requests = new Array<>(initialRequests); + private Layer lastLayer; + private int requestidx = 0; + private int iterateidx = 0; - for(int i = 0; i < requests.size; i ++){ - requests.set(i, new BlockRequest()); - } - } - - private class BlockRequest implements Comparable{ - Tile tile; - Layer layer; - - @Override - public int compareTo(BlockRequest other){ - return layer.compareTo(other.layer); - } + public BlockRenderer(){ + floorRenderer = new FloorRenderer(); - @Override - public String toString(){ - return tile.block().name + ":" + layer.toString(); - } - } - - /**Process all blocks to draw, simultaneously drawing block shadows and static blocks.*/ - public void processBlocks(){ - requestidx = 0; - lastLayer = null; - - int rangex = (int) (camera.viewportWidth * camera.zoom / tilesize / 2)+2; - int rangey = (int) (camera.viewportHeight * camera.zoom / tilesize / 2)+2; + for(int i = 0; i < requests.size; i++){ + requests.set(i, new BlockRequest()); + } + } - int expandr = 4; - - Graphics.surface(renderer.effectSurface); + /** + * Process all blocks to draw, simultaneously drawing block shadows and static blocks. + */ + public void processBlocks(){ + requestidx = 0; + lastLayer = null; - int avgx = Mathf.scl(camera.position.x, tilesize); - int avgy = Mathf.scl(camera.position.y, tilesize); + int rangex = (int) (camera.viewportWidth * camera.zoom / tilesize / 2) + 2; + int rangey = (int) (camera.viewportHeight * camera.zoom / tilesize / 2) + 2; - int minx = Math.max(avgx - rangex - expandr, 0); - int miny = Math.max(avgy - rangey - expandr, 0); - int maxx = Math.min(world.width() - 1, avgx + rangex + expandr); - int maxy = Math.min(world.height() - 1, avgy+ rangey + expandr); + int expandr = 4; - for(int x = minx; x <= maxx; x++){ - for(int y = miny; y <= maxy; y++){ - boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey); + Graphics.surface(renderer.effectSurface, true, false); - synchronized (Tile.tileSetLock) { - Tile tile = world.rawTile(x, y); + int avgx = Mathf.scl(camera.position.x, tilesize); + int avgy = Mathf.scl(camera.position.y, tilesize); - if (tile != null) { - Block block = tile.block(); + int minx = Math.max(avgx - rangex - expandr, 0); + int miny = Math.max(avgy - rangey - expandr, 0); + int maxx = Math.min(world.width() - 1, avgx + rangex + expandr); + int maxy = Math.min(world.height() - 1, avgy + rangey + expandr); - if (!expanded && block != Blocks.air && world.isAccessible(x, y)) { - tile.block().drawShadow(tile); - } + for(int x = minx; x <= maxx; x++){ + for(int y = miny; y <= maxy; y++){ + boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey); - if (!(block instanceof StaticBlock)) { - if (block != Blocks.air) { - if (!expanded) { - addRequest(tile, Layer.block); - } + synchronized(Tile.tileSetLock){ + Tile tile = world.rawTile(x, y); - if (block.expanded || !expanded) { - if (block.layer != null && block.isLayer(tile)) { - addRequest(tile, block.layer); - } + if(tile != null){ + Block block = tile.block(); - if (block.layer2 != null && block.isLayer2(tile)) { - addRequest(tile, block.layer2); - } - } - } - } - } - } - } - } + if(!expanded && block != Blocks.air && world.isAccessible(x, y)){ + tile.block().drawShadow(tile); + } - //TODO this actually isn't necessary - Draw.color(0, 0, 0, 0.15f); - Graphics.flushSurface(); - Draw.color(); + if(!(block instanceof StaticBlock)){ + if(block != Blocks.air){ + if(!expanded){ + addRequest(tile, Layer.block); + } - Graphics.end(); - floorRenderer.beginDraw(); - floorRenderer.drawLayer(CacheLayer.walls); - floorRenderer.endDraw(); - Graphics.begin(); + if(block.expanded || !expanded){ + if(block.layer != null && block.isLayer(tile)){ + addRequest(tile, block.layer); + } - Sort.instance().sort(requests.items, 0, requestidx); - iterateidx = 0; - } + if(block.layer2 != null && block.isLayer2(tile)){ + addRequest(tile, block.layer2); + } + } + } + } + } + } + } + } - public int getRequests(){ - return requestidx; - } - - public void drawBlocks(Layer stopAt){ - - for(; iterateidx < requestidx; iterateidx ++){ + //TODO this actually isn't necessary + Draw.color(0, 0, 0, 0.15f); + Graphics.flushSurface(); + Draw.color(); - if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ - break; - } - - BlockRequest req = requests.get(iterateidx); + Graphics.end(); + floorRenderer.beginDraw(); + floorRenderer.drawLayer(CacheLayer.walls); + floorRenderer.endDraw(); + Graphics.begin(); - if(req.layer != lastLayer){ - if(lastLayer != null) layerEnds(lastLayer); - layerBegins(req.layer); - } + Sort.instance().sort(requests.items, 0, requestidx); + iterateidx = 0; + } - synchronized (Tile.tileSetLock) { - Block block = req.tile.block(); + public int getRequests(){ + return requestidx; + } - if (req.layer == Layer.block) { - block.draw(req.tile); - } else if (req.layer == block.layer) { - block.drawLayer(req.tile); - } else if (req.layer == block.layer2) { - block.drawLayer2(req.tile); - } - } + public void drawBlocks(Layer stopAt){ - lastLayer = req.layer; - } - } + for(; iterateidx < requestidx; iterateidx++){ - public void drawTeamBlocks(Layer layer, Team team){ - int index = this.iterateidx; + if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ + break; + } - for(; index < requestidx; index ++){ + BlockRequest req = requests.get(iterateidx); - if(index < requests.size && requests.get(index).layer.ordinal() > layer.ordinal()){ - break; - } + if(req.layer != lastLayer){ + if(lastLayer != null) layerEnds(lastLayer); + layerBegins(req.layer); + } - BlockRequest req = requests.get(index); - if(req.tile.getTeam() != team) continue; + synchronized(Tile.tileSetLock){ + Block block = req.tile.block(); - synchronized (Tile.tileSetLock) { - Block block = req.tile.block(); + if(req.layer == Layer.block){ + block.draw(req.tile); + }else if(req.layer == block.layer){ + block.drawLayer(req.tile); + }else if(req.layer == block.layer2){ + block.drawLayer2(req.tile); + } + } - if (req.layer == block.layer) { - block.drawLayer(req.tile); - } else if (req.layer == block.layer2) { - block.drawLayer2(req.tile); - } - } - } - } + lastLayer = req.layer; + } + } - public void skipLayer(Layer stopAt){ + public void drawTeamBlocks(Layer layer, Team team){ + int index = this.iterateidx; - for(; iterateidx < requestidx; iterateidx ++){ - if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ - break; - } - } - } + for(; index < requestidx; index++){ - public void beginFloor(){ - floorRenderer.beginDraw(); - } + if(index < requests.size && requests.get(index).layer.ordinal() > layer.ordinal()){ + break; + } - public void endFloor(){ - floorRenderer.endDraw(); - } + BlockRequest req = requests.get(index); + if(req.tile.getTeam() != team) continue; - public void drawFloor(){ - floorRenderer.drawFloor(); - } + synchronized(Tile.tileSetLock){ + Block block = req.tile.block(); - private void layerBegins(Layer layer){} + if(req.layer == block.layer){ + block.drawLayer(req.tile); + }else if(req.layer == block.layer2){ + block.drawLayer2(req.tile); + } + } + } + } - private void layerEnds(Layer layer){} + public void skipLayer(Layer stopAt){ - private void addRequest(Tile tile, Layer layer){ - if(requestidx >= requests.size){ - requests.add(new BlockRequest()); - } - BlockRequest r = requests.get(requestidx); - if(r == null){ - requests.set(requestidx, r = new BlockRequest()); - } - r.tile = tile; - r.layer = layer; - requestidx ++; - } + for(; iterateidx < requestidx; iterateidx++){ + if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ + break; + } + } + } + + public void beginFloor(){ + floorRenderer.beginDraw(); + } + + public void endFloor(){ + floorRenderer.endDraw(); + } + + public void drawFloor(){ + floorRenderer.drawFloor(); + } + + private void layerBegins(Layer layer){ + } + + private void layerEnds(Layer layer){ + } + + private void addRequest(Tile tile, Layer layer){ + if(requestidx >= requests.size){ + requests.add(new BlockRequest()); + } + BlockRequest r = requests.get(requestidx); + if(r == null){ + requests.set(requestidx, r = new BlockRequest()); + } + r.tile = tile; + r.layer = layer; + requestidx++; + } + + private class BlockRequest implements Comparable{ + Tile tile; + Layer layer; + + @Override + public int compareTo(BlockRequest other){ + return layer.compareTo(other.layer); + } + + @Override + public String toString(){ + return tile.block().name + ":" + layer.toString(); + } + } } diff --git a/core/src/io/anuke/mindustry/graphics/CacheLayer.java b/core/src/io/anuke/mindustry/graphics/CacheLayer.java index 623497e912..aecf703ae2 100644 --- a/core/src/io/anuke/mindustry/graphics/CacheLayer.java +++ b/core/src/io/anuke/mindustry/graphics/CacheLayer.java @@ -8,7 +8,7 @@ import io.anuke.ucore.graphics.Shader; import static io.anuke.mindustry.Vars.renderer; -public enum CacheLayer { +public enum CacheLayer{ water{ @Override public void begin(){ @@ -57,25 +57,24 @@ public enum CacheLayer { walls; public void begin(){ - + } public void end(){ - + } protected void beginShader(){ //renderer.getBlocks().endFloor(); - renderer.effectSurface.getBuffer().begin(); + renderer.effectSurface.getBuffer().bind(); Graphics.clear(Color.CLEAR); //renderer.getBlocks().beginFloor(); } public void endShader(Shader shader){ renderer.getBlocks().endFloor(); - renderer.effectSurface.getBuffer().end(); - renderer.pixelSurface.getBuffer().begin(); + renderer.pixelSurface.getBuffer().bind(); Graphics.shader(shader); Graphics.begin(); diff --git a/core/src/io/anuke/mindustry/graphics/FloorRenderer.java b/core/src/io/anuke/mindustry/graphics/FloorRenderer.java index a93bde5a6f..5ccefa23be 100644 --- a/core/src/io/anuke/mindustry/graphics/FloorRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/FloorRenderer.java @@ -26,7 +26,7 @@ import java.util.Arrays; import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class FloorRenderer { +public class FloorRenderer{ private final static int chunksize = 64; private Chunk[][] cache; @@ -38,6 +38,35 @@ public class FloorRenderer { Events.on(WorldLoadGraphicsEvent.class, this::clearTiles); } + static ShaderProgram createDefaultShader(){ + String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // + + "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // + + "uniform mat4 u_projTrans;\n" // + + "varying vec2 v_texCoords;\n" // + + "\n" // + + "void main()\n" // + + "{\n" // + + " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // + + " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // + + "}\n"; + String fragmentShader = "#ifdef GL_ES\n" // + + "#define LOWP lowp\n" // + + "precision mediump float;\n" // + + "#else\n" // + + "#define LOWP \n" // + + "#endif\n" // + + "varying vec2 v_texCoords;\n" // + + "uniform sampler2D u_texture;\n" // + + "void main()\n"// + + "{\n" // + + " gl_FragColor = texture2D(u_texture, v_texCoords);\n" // + + "}"; + + ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader); + if(!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog()); + return shader; + } + public void drawFloor(){ if(cache == null){ return; @@ -45,11 +74,11 @@ public class FloorRenderer { OrthographicCamera camera = Core.camera; - int crangex = (int)(camera.viewportWidth * camera.zoom / (chunksize * tilesize))+1; - int crangey = (int)(camera.viewportHeight * camera.zoom / (chunksize * tilesize))+1; + int crangex = (int) (camera.viewportWidth * camera.zoom / (chunksize * tilesize)) + 1; + int crangey = (int) (camera.viewportHeight * camera.zoom / (chunksize * tilesize)) + 1; - for(int x = -crangex; x <= crangex; x++) { - for (int y = -crangey; y <= crangey; y++) { + for(int x = -crangex; x <= crangex; x++){ + for(int y = -crangey; y <= crangey; y++){ int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x; int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y; @@ -71,13 +100,13 @@ public class FloorRenderer { int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x; int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y; - if (!Mathf.inBounds(worldx, worldy, cache)) + if(!Mathf.inBounds(worldx, worldy, cache)) continue; Chunk chunk = cache[worldx][worldy]; //loop through all layers, and add layer index if it exists - for(int i = 0; i < layers - 1; i ++){ + for(int i = 0; i < layers - 1; i++){ if(chunk.caches[i] != -1){ drawnLayerSet.add(i); } @@ -95,7 +124,7 @@ public class FloorRenderer { Graphics.end(); beginDraw(); - for(int i = 0; i < drawnLayers.size; i ++) { + for(int i = 0; i < drawnLayers.size; i++){ CacheLayer layer = CacheLayer.values()[drawnLayers.get(i)]; drawLayer(layer); @@ -131,13 +160,13 @@ public class FloorRenderer { OrthographicCamera camera = Core.camera; - int crangex = (int)(camera.viewportWidth * camera.zoom / (chunksize * tilesize))+1; - int crangey = (int)(camera.viewportHeight * camera.zoom / (chunksize * tilesize))+1; + int crangex = (int) (camera.viewportWidth * camera.zoom / (chunksize * tilesize)) + 1; + int crangey = (int) (camera.viewportHeight * camera.zoom / (chunksize * tilesize)) + 1; layer.begin(); - for (int x = -crangex; x <= crangex; x++) { - for (int y = -crangey; y <= crangey; y++) { + for(int x = -crangex; x <= crangex; x++){ + for(int y = -crangey; y <= crangey; y++){ int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x; int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y; @@ -166,12 +195,12 @@ public class FloorRenderer { ObjectSet used = new ObjectSet<>(); - for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++) { - for (int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++) { + for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){ + for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){ Tile tile = world.tile(tilex, tiley); - if (tile != null){ + if(tile != null){ used.add(tile.block().cacheLayer == CacheLayer.walls ? - CacheLayer.walls : tile.floor().cacheLayer); + CacheLayer.walls : tile.floor().cacheLayer); } } } @@ -180,7 +209,7 @@ public class FloorRenderer { cacheChunkLayer(cx, cy, chunk, layer); } - // Log.info("Time to cache a chunk: {0}", TimeUtils.timeSinceNanos(time) / 1000000f); + // Log.info("Time to cache a chunk: {0}", TimeUtils.timeSinceNanos(time) / 1000000f); } private void cacheChunkLayer(int cx, int cy, Chunk chunk, CacheLayer layer){ @@ -211,25 +240,21 @@ public class FloorRenderer { chunk.caches[layer.ordinal()] = cbatch.getLastCache(); } - private class Chunk{ - int[] caches = new int[CacheLayer.values().length]; - } - public void clearTiles(){ if(cbatch != null) cbatch.dispose(); Timers.mark(); - int chunksx = Mathf.ceil((float)world.width() / chunksize), chunksy = Mathf.ceil((float)world.height() / chunksize); + int chunksx = Mathf.ceil((float) world.width() / chunksize), chunksy = Mathf.ceil((float) world.height() / chunksize); cache = new Chunk[chunksx][chunksy]; - cbatch = new CacheBatch(world.width()*world.height()*4*4); + cbatch = new CacheBatch(world.width() * world.height() * 4 * 4); Log.info("Time to create: {0}", Timers.elapsed()); Timers.mark(); - for (int x = 0; x < chunksx; x++) { - for (int y = 0; y < chunksy; y++) { + for(int x = 0; x < chunksx; x++){ + for(int y = 0; y < chunksy; y++){ cache[x][y] = new Chunk(); Arrays.fill(cache[x][y].caches, -1); @@ -240,32 +265,7 @@ public class FloorRenderer { Log.info("Time to cache: {0}", Timers.elapsed()); } - static ShaderProgram createDefaultShader () { - String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // - + "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // - + "uniform mat4 u_projTrans;\n" // - + "varying vec2 v_texCoords;\n" // - + "\n" // - + "void main()\n" // - + "{\n" // - + " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // - + " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // - + "}\n"; - String fragmentShader = "#ifdef GL_ES\n" // - + "#define LOWP lowp\n" // - + "precision mediump float;\n" // - + "#else\n" // - + "#define LOWP \n" // - + "#endif\n" // - + "varying vec2 v_texCoords;\n" // - + "uniform sampler2D u_texture;\n" // - + "void main()\n"// - + "{\n" // - + " gl_FragColor = texture2D(u_texture, v_texCoords);\n" // - + "}"; - - ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader); - if (!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog()); - return shader; + private class Chunk{ + int[] caches = new int[CacheLayer.values().length]; } } diff --git a/core/src/io/anuke/mindustry/graphics/FogRenderer.java b/core/src/io/anuke/mindustry/graphics/FogRenderer.java index 7d1d2048a4..6ebdfb8f90 100644 --- a/core/src/io/anuke/mindustry/graphics/FogRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/FogRenderer.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.graphics; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; @@ -23,7 +24,9 @@ import java.nio.ByteBuffer; import static io.anuke.mindustry.Vars.*; -/**Used for rendering fog of war. A framebuffer is used for this.*/ +/** + * Used for rendering fog of war. A framebuffer is used for this. + */ public class FogRenderer implements Disposable{ private TextureRegion region = new TextureRegion(); private FrameBuffer buffer; @@ -41,8 +44,8 @@ public class FogRenderer implements Disposable{ Graphics.clear(0, 0, 0, 1f); buffer.end(); - for (int x = 0; x < world.width(); x++) { - for (int y = 0; y < world.height(); y++) { + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ Tile tile = world.tile(x, y); if(tile.getTeam() == players[0].getTeam() && tile.block().synthetic() && tile.block().viewRange > 0){ @@ -65,14 +68,14 @@ public class FogRenderer implements Disposable{ float vw = Core.camera.viewportWidth * Core.camera.zoom; float vh = Core.camera.viewportHeight * Core.camera.zoom; - float px = Core.camera.position.x -= vw/2f; - float py = Core.camera.position.y -= vh/2f; + float px = Core.camera.position.x -= vw / 2f; + float py = Core.camera.position.y -= vh / 2f; float u = px / tilesize / world.width(); float v = py / tilesize / world.height(); - float u2 = (px + vw)/ tilesize / world.width(); - float v2 = (py + vh)/ tilesize / world.height(); + float u2 = (px + vw) / tilesize / world.width(); + float v2 = (py + vh) / tilesize / world.height(); if(Core.batch instanceof ClipSpriteBatch){ ((ClipSpriteBatch) Core.batch).enableClip(false); @@ -122,8 +125,8 @@ public class FogRenderer implements Disposable{ renderer.pixelSurface.getBuffer().end(); Graphics.shader(); - Graphics.begin(); - Core.batch.draw(renderer.pixelSurface.texture(), px, py + vh, vw, -vh); + Graphics.setScreen(); + Core.batch.draw(renderer.pixelSurface.texture(), 0, Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), -Gdx.graphics.getHeight()); Graphics.end(); if(Core.batch instanceof ClipSpriteBatch){ @@ -136,7 +139,7 @@ public class FogRenderer implements Disposable{ } @Override - public void dispose() { + public void dispose(){ if(buffer != null) buffer.dispose(); } } diff --git a/core/src/io/anuke/mindustry/graphics/Layer.java b/core/src/io/anuke/mindustry/graphics/Layer.java index 3bf5949605..f04144a2cd 100644 --- a/core/src/io/anuke/mindustry/graphics/Layer.java +++ b/core/src/io/anuke/mindustry/graphics/Layer.java @@ -1,16 +1,28 @@ package io.anuke.mindustry.graphics; public enum Layer{ - /**Base block layer.*/ - block, - /**for placement*/ + /** + * Base block layer. + */ + block, + /** + * for placement + */ placement, - /**First overlay. Stuff like conveyor items.*/ - overlay, - /**"High" blocks, like turrets.*/ - turret, - /**Power lasers.*/ - power, - /**Extra lasers, like healing turrets.*/ - laser + /** + * First overlay. Stuff like conveyor items. + */ + overlay, + /** + * "High" blocks, like turrets. + */ + turret, + /** + * Power lasers. + */ + power, + /** + * Extra lasers, like healing turrets. + */ + laser } diff --git a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java index c3a13df75e..2760dbdc78 100644 --- a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java @@ -54,7 +54,7 @@ public class MinimapRenderer implements Disposable{ public void zoomBy(int amount){ zoom += amount; - zoom = Mathf.clamp(zoom, 1, Math.min(world.width(), world.height())/baseSize/2); + zoom = Mathf.clamp(zoom, 1, Math.min(world.width(), world.height()) / baseSize / 2); } public void reset(){ @@ -71,10 +71,10 @@ public class MinimapRenderer implements Disposable{ int sz = baseSize * zoom; float dx = (Core.camera.position.x / tilesize); float dy = (Core.camera.position.y / tilesize); - dx = Mathf.clamp(dx, sz, world.width()-sz); - dy = Mathf.clamp(dy, sz, world.height()-sz); + dx = Mathf.clamp(dx, sz, world.width() - sz); + dy = Mathf.clamp(dy, sz, world.height() - sz); - synchronized (units){ + synchronized(units){ rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); Graphics.flush(); @@ -93,24 +93,24 @@ public class MinimapRenderer implements Disposable{ } } - public TextureRegion getRegion() { + public TextureRegion getRegion(){ if(texture == null) return null; int sz = Mathf.clamp(baseSize * zoom, baseSize, Math.min(world.width(), world.height())); float dx = (Core.camera.position.x / tilesize); float dy = (Core.camera.position.y / tilesize); - dx = Mathf.clamp(dx, sz, world.width()-sz); - dy = Mathf.clamp(dy, sz, world.height()-sz); + dx = Mathf.clamp(dx, sz, world.width() - sz); + dy = Mathf.clamp(dy, sz, world.height() - sz); float invTexWidth = 1f / texture.getWidth(); float invTexHeight = 1f / texture.getHeight(); - float x = dx - sz, y = world.height()-dy - sz, width = sz*2, height = sz*2; + float x = dx - sz, y = world.height() - dy - sz, width = sz * 2, height = sz * 2; region.setRegion(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight); return region; } public void updateAll(){ - for(int x = 0; x < world.width(); x ++){ - for(int y = 0; y < world.height(); y ++){ + for(int x = 0; x < world.width(); x++){ + for(int y = 0; y < world.height(); y++){ pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, colorFor(world.tile(x, y))); } } @@ -121,7 +121,6 @@ public class MinimapRenderer implements Disposable{ int color = colorFor(world.tile(tile.x, tile.y)); pixmap.drawPixel(tile.x, pixmap.getHeight() - 1 - tile.y, color); - texture.bind(); Pixmaps.drawPixel(texture, tile.x, pixmap.getHeight() - 1 - tile.y, color); } @@ -129,10 +128,10 @@ public class MinimapRenderer implements Disposable{ int sz = baseSize * zoom; float dx = (Core.camera.position.x / tilesize); float dy = (Core.camera.position.y / tilesize); - dx = Mathf.clamp(dx, sz, world.width()-sz); - dy = Mathf.clamp(dy, sz, world.height()-sz); + dx = Mathf.clamp(dx, sz, world.width() - sz); + dy = Mathf.clamp(dy, sz, world.height() - sz); - synchronized (units) { + synchronized(units){ rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); units.clear(); Units.getNearby(rect, units::add); @@ -143,7 +142,7 @@ public class MinimapRenderer implements Disposable{ int color = tile.breakable() ? tile.target().getTeam().intColor : ColorMapper.getBlockColor(tile.block()); if(color == 0) color = ColorMapper.getBlockColor(tile.floor()); if(tile.elevation > 0){ - float mul = 1.1f+tile.elevation/4f; + float mul = 1.1f + tile.elevation / 4f; tmpColor.set(color); tmpColor.mul(mul, mul, mul, 1f); color = Color.rgba8888(tmpColor); @@ -152,7 +151,7 @@ public class MinimapRenderer implements Disposable{ } @Override - public void dispose() { + public void dispose(){ pixmap.dispose(); texture.dispose(); texture = null; diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index 53aeee4a9b..d207cb61b4 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -24,10 +24,10 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; -public class OverlayRenderer { +public class OverlayRenderer{ public void drawBottom(){ - for(Player player : players) { + for(Player player : players){ InputHandler input = control.input(player.playerIndex); if(!input.isDrawing() || player.isDead()) continue; @@ -43,7 +43,7 @@ public class OverlayRenderer { public void drawTop(){ - for(Player player : players) { + for(Player player : players){ if(player.isDead()) continue; //dead player don't draw InputHandler input = control.input(player.playerIndex); @@ -52,7 +52,7 @@ public class OverlayRenderer { if(input.frag.config.isShown()){ Tile tile = input.frag.config.getSelectedTile(); - synchronized (Tile.tileSetLock) { + synchronized(Tile.tileSetLock){ tile.block().drawConfigure(tile); } } @@ -62,14 +62,14 @@ public class OverlayRenderer { Draw.reset(); //draw selected block bars and info - if (input.recipe == null && !ui.hasMouse() && !input.frag.config.isShown()) { + if(input.recipe == null && !ui.hasMouse() && !input.frag.config.isShown()){ Vector2 vec = Graphics.world(input.getMouseX(), input.getMouseY()); Tile tile = world.tileWorld(vec.x, vec.y); - if (tile != null && tile.block() != Blocks.air) { + if(tile != null && tile.block() != Blocks.air){ Tile target = tile.target(); - if (showBlockDebug && target.entity != null) { + if(showBlockDebug && target.entity != null){ Draw.color(Color.RED); Lines.crect(target.drawx(), target.drawy(), target.block().size * tilesize, target.block().size * tilesize); Vector2 v = new Vector2(); @@ -78,7 +78,7 @@ public class OverlayRenderer { Draw.tscl(0.25f); Array arr = target.block().getDebugInfo(target); StringBuilder result = new StringBuilder(); - for (int i = 0; i < arr.size / 2; i++) { + for(int i = 0; i < arr.size / 2; i++){ result.append(arr.get(i * 2)); result.append(": "); result.append(arr.get(i * 2 + 1)); @@ -92,27 +92,27 @@ public class OverlayRenderer { Draw.reset(); } - synchronized (Tile.tileSetLock) { + synchronized(Tile.tileSetLock){ Block block = target.block(); TileEntity entity = target.entity; - if (entity != null) { + if(entity != null){ int[] values = {0, 0}; boolean[] doDraw = {false}; Callable drawbars = () -> { - for (BlockBar bar : block.bars.list()) { + for(BlockBar bar : block.bars.list()){ float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1])); float value = bar.value.get(target); - if (MathUtils.isEqual(value, -1f)) continue; + if(MathUtils.isEqual(value, -1f)) continue; if(doDraw[0]){ drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value); } - if (bar.top) + if(bar.top) values[0]++; else values[1]++; @@ -122,11 +122,11 @@ public class OverlayRenderer { drawbars.run(); if(values[0] > 0){ - drawEncloser(target.drawx(), target.drawy() + block.size * tilesize/2f + 2f, values[0]); + drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]); } if(values[1] > 0){ - drawEncloser(target.drawx(), target.drawy() - block.size * tilesize/2f - 2f - values[1], values[1]); + drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]); } doDraw[0] = true; @@ -142,7 +142,7 @@ public class OverlayRenderer { } } - if (input.isDroppingItem()) { + if(input.isDroppingItem()){ Vector2 v = Graphics.world(input.getMouseX(), input.getMouseY()); float size = 8; Draw.rect(player.inventory.getItem().item.region, v.x, v.y, size, size); @@ -151,8 +151,8 @@ public class OverlayRenderer { Draw.reset(); Tile tile = world.tileWorld(v.x, v.y); - if (tile != null) tile = tile.target(); - if (tile != null && tile.block().acceptStack(player.inventory.getItem().item, player.inventory.getItem().amount, tile, player) > 0) { + if(tile != null) tile = tile.target(); + if(tile != null && tile.block().acceptStack(player.inventory.getItem().item, player.inventory.getItem().amount, tile, player) > 0){ Draw.color(Palette.place); Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1 + Mathf.absin(Timers.time(), 5f, 1f)); Draw.color(); @@ -176,9 +176,9 @@ public class OverlayRenderer { float x = unit.x; float y = unit.y; - if(unit == players[0] && players.length == 1 && snapCamera) { - x = (int)(x + 0.0001f); - y = (int)(y + 0.0001f); + if(unit == players[0] && players.length == 1 && snapCamera){ + x = (int) (x + 0.0001f); + y = (int) (y + 0.0001f); } drawEncloser(x, y - 9f, 2f); @@ -193,25 +193,23 @@ public class OverlayRenderer { float len = 3; - float w = (int) (len * 2 * finion) + 0.5f; - - x -= 0.5f; - y += 0.5f; + float w = (int) (len * 2 * finion); Draw.color(Color.BLACK); - Lines.line(x - len + 1, y, x + len + 0.5f, y); - Draw.color(color); - if(w >= 1) - Lines.line(x - len + 1, y, x - len + w, y); - Draw.reset(); + Fill.crect(x - len, y, len * 2f, 1); + if(finion > 0){ + Draw.color(color); + Fill.crect(x - len, y, Math.max(1, w), 1); + } + Draw.color(); } void drawEncloser(float x, float y, float height){ - float len = 3; + float len = 4; Draw.color(Palette.bar); - Fill.crect(x - len - 1, y - 1, len*2f + 2f, height + 2f); + Fill.crect(x - len, y - 1, len * 2f, height + 2f); Draw.color(); } } diff --git a/core/src/io/anuke/mindustry/graphics/Palette.java b/core/src/io/anuke/mindustry/graphics/Palette.java index b717d2441f..1f369df6f2 100644 --- a/core/src/io/anuke/mindustry/graphics/Palette.java +++ b/core/src/io/anuke/mindustry/graphics/Palette.java @@ -2,7 +2,7 @@ package io.anuke.mindustry.graphics; import com.badlogic.gdx.graphics.Color; -public class Palette { +public class Palette{ public static final Color bulletYellow = Color.valueOf("ffeec9"); public static final Color bulletYellowBack = Color.valueOf("f9c87a"); diff --git a/core/src/io/anuke/mindustry/graphics/Shaders.java b/core/src/io/anuke/mindustry/graphics/Shaders.java index 21c02966f5..996d8e07fe 100644 --- a/core/src/io/anuke/mindustry/graphics/Shaders.java +++ b/core/src/io/anuke/mindustry/graphics/Shaders.java @@ -13,100 +13,100 @@ import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; public class Shaders{ - public static Outline outline; + public static Outline outline; public static BlockBuild blockbuild; public static BlockPreview blockpreview; - public static Shield shield; - public static SurfaceShader water; - public static SurfaceShader lava; - public static SurfaceShader oil; - public static Space space; - public static UnitBuild build; - public static MixShader mix; - public static Shader fullMix; - public static FogShader fog; + public static Shield shield; + public static SurfaceShader water; + public static SurfaceShader lava; + public static SurfaceShader oil; + public static Space space; + public static UnitBuild build; + public static MixShader mix; + public static Shader fullMix; + public static FogShader fog; - public static void init(){ - outline = new Outline(); - blockbuild = new BlockBuild(); - blockpreview = new BlockPreview(); - shield = new Shield(); - water = new SurfaceShader("water"); - lava = new SurfaceShader("lava"); - oil = new SurfaceShader("oil"); - space = new Space(); - build = new UnitBuild(); - mix = new MixShader(); - fog = new FogShader(); - fullMix = new Shader("fullmix", "default"); - } + public static void init(){ + outline = new Outline(); + blockbuild = new BlockBuild(); + blockpreview = new BlockPreview(); + shield = new Shield(); + water = new SurfaceShader("water"); + lava = new SurfaceShader("lava"); + oil = new SurfaceShader("oil"); + space = new Space(); + build = new UnitBuild(); + mix = new MixShader(); + fog = new FogShader(); + fullMix = new Shader("fullmix", "default"); + } - public static class FogShader extends Shader{ - public FogShader(){ - super("fog", "default"); - } - } + public static class FogShader extends Shader{ + public FogShader(){ + super("fog", "default"); + } + } - public static class MixShader extends Shader{ - public Color color = new Color(Color.WHITE); + public static class MixShader extends Shader{ + public Color color = new Color(Color.WHITE); - public MixShader(){ - super("mix", "default"); - } + public MixShader(){ + super("mix", "default"); + } - @Override - public void apply() { - super.apply(); - shader.setUniformf("u_color", color); - } - } + @Override + public void apply(){ + super.apply(); + shader.setUniformf("u_color", color); + } + } - public static class Space extends SurfaceShader{ + public static class Space extends SurfaceShader{ - public Space(){ - super("space2"); - } + public Space(){ + super("space2"); + } - @Override - public void apply(){ - super.apply(); - shader.setUniformf("u_center", world.width() * tilesize/2f, world.height() * tilesize/2f); - } - } + @Override + public void apply(){ + super.apply(); + shader.setUniformf("u_center", world.width() * tilesize / 2f, world.height() * tilesize / 2f); + } + } - public static class UnitBuild extends Shader{ - public float progress, time; - public Color color = new Color(); - public TextureRegion region; + public static class UnitBuild extends Shader{ + public float progress, time; + public Color color = new Color(); + public TextureRegion region; - public UnitBuild() { - super("build", "default"); - } + public UnitBuild(){ + super("build", "default"); + } - @Override - public void apply(){ - shader.setUniformf("u_time", time); - shader.setUniformf("u_color", color); - shader.setUniformf("u_progress", progress); - shader.setUniformf("u_uv", region.getU(), region.getV()); - shader.setUniformf("u_uv2", region.getU2(), region.getV2()); - shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight()); - } - } + @Override + public void apply(){ + shader.setUniformf("u_time", time); + shader.setUniformf("u_color", color); + shader.setUniformf("u_progress", progress); + shader.setUniformf("u_uv", region.getU(), region.getV()); + shader.setUniformf("u_uv2", region.getU2(), region.getV2()); + shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight()); + } + } - public static class Outline extends Shader{ - public Color color = new Color(); + public static class Outline extends Shader{ + public Color color = new Color(); - public Outline(){ - super("outline", "default"); - } - - @Override - public void apply(){ - shader.setUniformf("u_color", color); - shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight()); - } - } + public Outline(){ + super("outline", "default"); + } + + @Override + public void apply(){ + shader.setUniformf("u_color", color); + shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight()); + } + } public static class BlockBuild extends Shader{ public Color color = new Color(); @@ -136,7 +136,7 @@ public class Shaders{ @Override public void apply(){ - // shader.setUniformf("u_progress", progress); + // shader.setUniformf("u_progress", progress); shader.setUniformf("u_color", color); shader.setUniformf("u_uv", region.getU(), region.getV()); shader.setUniformf("u_uv2", region.getU2(), region.getV2()); @@ -144,49 +144,49 @@ public class Shaders{ shader.setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight()); } } - - public static class Shield extends Shader{ - public static final int MAX_HITS = 3*64; - public Color color = new Color(); - public FloatArray hits; - - public Shield(){ - super("shield", "default"); - } - - @Override - public void apply(){ - float scaling = Core.cameraScale / 4f / Core.camera.zoom; - if(hits.size > 0){ - shader.setUniform3fv("u_hits[0]", hits.items, 0, Math.min(hits.size, MAX_HITS)); - shader.setUniformi("u_hitamount", Math.min(hits.size, MAX_HITS)/3); - } - shader.setUniformf("u_dp", Unit.dp.scl(1f)); - shader.setUniformf("u_color", color); - shader.setUniformf("u_time", Timers.time() / Unit.dp.scl(1f)); - shader.setUniformf("u_scaling", scaling); - shader.setUniformf("u_offset", - Core.camera.position.x - Core.camera.viewportWidth/2 * Core.camera.zoom, - Core.camera.position.y - Core.camera.viewportHeight/2 * Core.camera.zoom); - shader.setUniformf("u_texsize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom, - Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom); - } - } - public static class SurfaceShader extends Shader{ + public static class Shield extends Shader{ + public static final int MAX_HITS = 3 * 64; + public Color color = new Color(); + public FloatArray hits; - public SurfaceShader(String frag){ - super(frag, "default"); - } + public Shield(){ + super("shield", "default"); + } - @Override - public void apply(){ - shader.setUniformf("camerapos", - Core.camera.position.x - Core.camera.viewportWidth/2 * Core.camera.zoom, - Core.camera.position.y - Core.camera.viewportHeight/2 * Core.camera.zoom); - shader.setUniformf("screensize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom, - Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom); - shader.setUniformf("time", Timers.time()); - } - } + @Override + public void apply(){ + float scaling = Core.cameraScale / 4f / Core.camera.zoom; + if(hits.size > 0){ + shader.setUniform3fv("u_hits[0]", hits.items, 0, Math.min(hits.size, MAX_HITS)); + shader.setUniformi("u_hitamount", Math.min(hits.size, MAX_HITS) / 3); + } + shader.setUniformf("u_dp", Unit.dp.scl(1f)); + shader.setUniformf("u_color", color); + shader.setUniformf("u_time", Timers.time() / Unit.dp.scl(1f)); + shader.setUniformf("u_scaling", scaling); + shader.setUniformf("u_offset", + Core.camera.position.x - Core.camera.viewportWidth / 2 * Core.camera.zoom, + Core.camera.position.y - Core.camera.viewportHeight / 2 * Core.camera.zoom); + shader.setUniformf("u_texsize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom, + Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom); + } + } + + public static class SurfaceShader extends Shader{ + + public SurfaceShader(String frag){ + super(frag, "default"); + } + + @Override + public void apply(){ + shader.setUniformf("camerapos", + Core.camera.position.x - Core.camera.viewportWidth / 2 * Core.camera.zoom, + Core.camera.position.y - Core.camera.viewportHeight / 2 * Core.camera.zoom); + shader.setUniformf("screensize", Gdx.graphics.getWidth() / Core.cameraScale * Core.camera.zoom, + Gdx.graphics.getHeight() / Core.cameraScale * Core.camera.zoom); + shader.setUniformf("time", Timers.time()); + } + } } diff --git a/core/src/io/anuke/mindustry/graphics/Trail.java b/core/src/io/anuke/mindustry/graphics/Trail.java index 04389cd44b..badf28a389 100644 --- a/core/src/io/anuke/mindustry/graphics/Trail.java +++ b/core/src/io/anuke/mindustry/graphics/Trail.java @@ -8,8 +8,10 @@ import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Mathf; -/**Class that renders a trail.*/ -public class Trail { +/** + * Class that renders a trail. + */ +public class Trail{ private final static float maxJump = 15f; private final int length; private final FloatArray points = new FloatArray(); @@ -26,7 +28,7 @@ public class Trail { points.add(curx, cury); - if(points.size > length*2) { + if(points.size > length * 2){ float[] items = points.items; System.arraycopy(items, 2, items, 0, points.size - 2); points.size -= 2; @@ -40,27 +42,24 @@ public class Trail { points.clear(); } - public synchronized void draw(Color start, Color end, float stroke){ + public synchronized void draw(Color color, float stroke){ + Draw.color(color); for(int i = 0; i < points.size - 2; i += 2){ float x = points.get(i); float y = points.get(i + 1); float x2 = points.get(i + 2); float y2 = points.get(i + 3); - float s = Mathf.clamp((float)(i) / points.size); - - Draw.color(start, end, s); + float s = Mathf.clamp((float) (i) / points.size); Lines.stroke(s * stroke); Lines.line(x, y, x2, y2); } if(points.size >= 2){ - Fill.circle(points.get(points.size-2), points.get(points.size-1), stroke/2f); + Fill.circle(points.get(points.size - 2), points.get(points.size - 1), stroke / 2f); } - Draw.color(start); - Draw.reset(); } } diff --git a/core/src/io/anuke/mindustry/input/CursorType.java b/core/src/io/anuke/mindustry/input/CursorType.java index fd55b7998e..3b8773f6cb 100644 --- a/core/src/io/anuke/mindustry/input/CursorType.java +++ b/core/src/io/anuke/mindustry/input/CursorType.java @@ -3,8 +3,10 @@ package io.anuke.mindustry.input; import io.anuke.ucore.function.Callable; import io.anuke.ucore.scene.utils.Cursors; -/**Type of cursor for displaying on desktop.*/ -public enum CursorType { +/** + * Type of cursor for displaying on desktop. + */ +public enum CursorType{ normal(Cursors::restoreCursor), hand(Cursors::setHand), drill(() -> Cursors.set("drill")), @@ -16,7 +18,9 @@ public enum CursorType { this.call = call; } - /**Sets the current system cursor to this.*/ + /** + * Sets the current system cursor to this. + */ void set(){ call.run(); } diff --git a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java index 5c9bfafa21..94e07bf924 100644 --- a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java +++ b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java @@ -8,59 +8,58 @@ import io.anuke.ucore.core.KeyBinds; import io.anuke.ucore.core.KeyBinds.Category; import io.anuke.ucore.input.Input; -public class DefaultKeybinds { +public class DefaultKeybinds{ public static void load(){ String[] sections = {"player_1"}; - for(String section : sections) { + for(String section : sections){ KeyBinds.defaultSection(section, DeviceType.keyboard, - new Category("General"), - "move_x", new Axis(Input.A, Input.D), - "move_y", new Axis(Input.S, Input.W), - //"select", Input.MOUSE_LEFT, - //"break", Input.MOUSE_RIGHT, - //"shoot", Input.MOUSE_LEFT, - "rotate", new Axis(Input.SCROLL), - "dash", Input.SHIFT_LEFT, - "drop_unit", Input.SHIFT_LEFT, - new Category("View"), - "zoom_hold", Input.CONTROL_LEFT, - "zoom", new Axis(Input.SCROLL), - "zoom_minimap", new Axis(Input.MINUS, Input.PLUS), - "menu", Gdx.app.getType() == ApplicationType.Android ? Input.BACK : Input.ESCAPE, - "pause", Input.SPACE, - "toggle_menus", Input.C, - "item_withdraw", Input.SHIFT_LEFT, - new Category("Multiplayer"), - "player_list", Input.TAB, - "chat", Input.ENTER, - "chat_history_prev", Input.UP, - "chat_history_next", Input.DOWN, - "chat_scroll", new Axis(Input.SCROLL), - "console", Input.GRAVE + new Category("General"), + "move_x", new Axis(Input.A, Input.D), + "move_y", new Axis(Input.S, Input.W), + //"select", Input.MOUSE_LEFT, + //"break", Input.MOUSE_RIGHT, + //"shoot", Input.MOUSE_LEFT, + "rotate", new Axis(Input.SCROLL), + "dash", Input.SHIFT_LEFT, + "drop_unit", Input.SHIFT_LEFT, + new Category("View"), + "zoom_hold", Input.CONTROL_LEFT, + "zoom", new Axis(Input.SCROLL), + "zoom_minimap", new Axis(Input.MINUS, Input.PLUS), + "menu", Gdx.app.getType() == ApplicationType.Android ? Input.BACK : Input.ESCAPE, + "pause", Input.SPACE, + "toggle_menus", Input.C, + new Category("Multiplayer"), + "player_list", Input.TAB, + "chat", Input.ENTER, + "chat_history_prev", Input.UP, + "chat_history_next", Input.DOWN, + "chat_scroll", new Axis(Input.SCROLL), + "console", Input.GRAVE ); KeyBinds.defaultSection(section, DeviceType.controller, - new Category("General"), - "move_x", new Axis(Input.CONTROLLER_L_STICK_HORIZONTAL_AXIS), - "move_y", new Axis(Input.CONTROLLER_L_STICK_VERTICAL_AXIS), - "cursor_x", new Axis(Input.CONTROLLER_R_STICK_HORIZONTAL_AXIS), - "cursor_y", new Axis(Input.CONTROLLER_R_STICK_VERTICAL_AXIS), - //"select", Input.CONTROLLER_R_BUMPER, - //"break", Input.CONTROLLER_L_BUMPER, - //"shoot", Input.CONTROLLER_R_TRIGGER, - "dash", Input.CONTROLLER_Y, - "rotate_alt", new Axis(Input.CONTROLLER_DPAD_RIGHT, Input.CONTROLLER_DPAD_LEFT), - "rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B), - new Category("View"), - "zoom_hold", Input.ANY_KEY, - "zoom", new Axis(Input.CONTROLLER_DPAD_DOWN, Input.CONTROLLER_DPAD_UP), - "menu", Input.CONTROLLER_X, - "pause", Input.CONTROLLER_L_TRIGGER, - new Category("Multiplayer"), - "player_list", Input.CONTROLLER_START + new Category("General"), + "move_x", new Axis(Input.CONTROLLER_L_STICK_HORIZONTAL_AXIS), + "move_y", new Axis(Input.CONTROLLER_L_STICK_VERTICAL_AXIS), + "cursor_x", new Axis(Input.CONTROLLER_R_STICK_HORIZONTAL_AXIS), + "cursor_y", new Axis(Input.CONTROLLER_R_STICK_VERTICAL_AXIS), + //"select", Input.CONTROLLER_R_BUMPER, + //"break", Input.CONTROLLER_L_BUMPER, + //"shoot", Input.CONTROLLER_R_TRIGGER, + "dash", Input.CONTROLLER_Y, + "rotate_alt", new Axis(Input.CONTROLLER_DPAD_RIGHT, Input.CONTROLLER_DPAD_LEFT), + "rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B), + new Category("View"), + "zoom_hold", Input.ANY_KEY, + "zoom", new Axis(Input.CONTROLLER_DPAD_DOWN, Input.CONTROLLER_DPAD_UP), + "menu", Input.CONTROLLER_X, + "pause", Input.CONTROLLER_L_TRIGGER, + new Category("Multiplayer"), + "player_list", Input.CONTROLLER_START ); } diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index dc1d462627..a156939e1a 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -27,40 +27,49 @@ import static io.anuke.mindustry.input.CursorType.*; import static io.anuke.mindustry.input.PlaceMode.*; public class DesktopInput extends InputHandler{ - //controller info - private float controlx, controly; - private boolean controlling; private final String section; - - /**Current cursor type.*/ + //controller info + private float controlx, controly; + private boolean controlling; + /** + * Current cursor type. + */ private CursorType cursorType = normal; - /**Position where the player started dragging a line.*/ + /** + * Position where the player started dragging a line. + */ private int selectX, selectY; - /**Whether selecting mode is active.*/ + /** + * Whether selecting mode is active. + */ private PlaceMode mode; - /**Animation scale for line.*/ + /** + * Animation scale for line. + */ private float selectScale; - public DesktopInput(Player player){ - super(player); - this.section = "player_" + (player.playerIndex + 1); + public DesktopInput(Player player){ + super(player); + this.section = "player_" + (player.playerIndex + 1); } - /**Draws a placement icon for a specific block.*/ - void drawPlace(int x, int y, Block block, int rotation){ + /** + * Draws a placement icon for a specific block. + */ + void drawPlace(int x, int y, Block block, int rotation){ if(validPlace(x, y, block, rotation)){ Draw.color(); TextureRegion[] regions = block.getBlockIcon(); for(TextureRegion region : regions){ - Draw.rect(region, x *tilesize + block.offset(), y * tilesize + block.offset(), + Draw.rect(region, x * tilesize + block.offset(), y * tilesize + block.offset(), region.getRegionWidth() * selectScale, region.getRegionHeight() * selectScale, block.rotate ? rotation * 90 : 0); } }else{ Draw.color(Palette.remove); - Lines.square(x*tilesize + block.offset(), y*tilesize + block.offset(), block.size * tilesize/2f); + Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f); } } @@ -75,15 +84,15 @@ public class DesktopInput extends InputHandler{ if(cursor == null) return; - //draw selection(s) - if(mode == placing) { + //draw selection(s) + if(mode == placing){ NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursor.x, cursor.y, rotation, true, maxLength); - for (int i = 0; i <= result.getLength(); i += recipe.result.size) { + for(int i = 0; i <= result.getLength(); i += recipe.result.size){ int x = selectX + i * Mathf.sign(cursor.x - selectX) * Mathf.bool(result.isX()); int y = selectY + i * Mathf.sign(cursor.y - selectY) * Mathf.bool(!result.isX()); - if (i + recipe.result.size > result.getLength() && recipe.result.rotate) { + if(i + recipe.result.size > result.getLength() && recipe.result.rotate){ Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.remove : Palette.placeRotate); Draw.grect("place-arrow", x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), result.rotation * 90 - 90); @@ -99,37 +108,37 @@ public class DesktopInput extends InputHandler{ Draw.color(Palette.remove); - for(int x = dresult.x; x <= dresult.x2; x ++){ - for(int y = dresult.y; y <= dresult.y2; y ++){ + for(int x = dresult.x; x <= dresult.x2; x++){ + for(int y = dresult.y; y <= dresult.y2; y++){ Tile tile = world.tile(x, y); if(tile == null || !validBreak(tile.x, tile.y)) continue; tile = tile.target(); - Lines.poly(tile.drawx(), tile.drawy(), 4, tile.block().size * tilesize/2f, 45 + 15); + Lines.poly(tile.drawx(), tile.drawy(), 4, tile.block().size * tilesize / 2f, 45 + 15); } } Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); }else if(isPlacing()){ - if(recipe.result.rotate){ - Draw.color(!validPlace(cursor.x, cursor.y, recipe.result, rotation) ? Palette.remove : Palette.placeRotate); - Draw.grect("place-arrow", cursor.worldx() + recipe.result.offset(), + if(recipe.result.rotate){ + Draw.color(!validPlace(cursor.x, cursor.y, recipe.result, rotation) ? Palette.remove : Palette.placeRotate); + Draw.grect("place-arrow", cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), rotation * 90 - 90); } drawPlace(cursor.x, cursor.y, recipe.result, rotation); - recipe.result.drawPlace(cursor.x, cursor.y, rotation, validPlace(cursor.x, cursor.y, recipe.result, rotation)); + recipe.result.drawPlace(cursor.x, cursor.y, rotation, validPlace(cursor.x, cursor.y, recipe.result, rotation)); } Draw.reset(); } - @Override - public void update(){ + @Override + public void update(){ if(Net.active() && Inputs.keyTap("player_list")){ ui.listfrag.toggle(); } - if(player.isDead() || state.is(State.menu) || ui.hasDialog()) return; + if(player.isDead() || state.is(State.menu) || ui.hasDialog()) return; if(recipe != null && !Settings.getBool("desktop-place-help", false)){ ui.showInfo("Desktop controls have been changed.\nTo deselect a block or stop building, [accent]use the middle mouse button[]."); @@ -137,40 +146,40 @@ public class DesktopInput extends InputHandler{ Settings.save(); } - player.isBoosting = Inputs.keyDown("dash"); + player.isBoosting = Inputs.keyDown("dash"); - //deslect if not placing - if(!isPlacing() && mode == placing){ - mode = none; + //deslect if not placing + if(!isPlacing() && mode == placing){ + mode = none; } if(player.isShooting && !canShoot()){ - player.isShooting = false; + player.isShooting = false; } if(isPlacing()){ cursorType = hand; selectScale = Mathf.lerpDelta(selectScale, 1f, 0.2f); }else{ - selectScale = 0f; + selectScale = 0f; } - boolean controller = KeyBinds.getSection(section).device.type == DeviceType.controller; + boolean controller = KeyBinds.getSection(section).device.type == DeviceType.controller; - //zoom and rotate things - if(Inputs.getAxisActive("zoom") && (Inputs.keyDown(section,"zoom_hold") || controller)){ - renderer.scaleCamera((int) Inputs.getAxisTapped(section, "zoom")); - } + //zoom and rotate things + if(Inputs.getAxisActive("zoom") && (Inputs.keyDown(section, "zoom_hold") || controller)){ + renderer.scaleCamera((int) Inputs.getAxisTapped(section, "zoom")); + } - renderer.minimap().zoomBy(-(int)Inputs.getAxisTapped(section,"zoom_minimap")); - rotation = Mathf.mod(rotation + (int)Inputs.getAxisTapped(section,"rotate"), 4); + renderer.minimap().zoomBy(-(int) Inputs.getAxisTapped(section, "zoom_minimap")); + rotation = Mathf.mod(rotation + (int) Inputs.getAxisTapped(section, "rotate"), 4); - Tile cursor = tileAt(control.gdxInput().getX(), control.gdxInput().getY()); + Tile cursor = tileAt(control.gdxInput().getX(), control.gdxInput().getY()); - if(player.isDead()){ + if(player.isDead()){ cursorType = normal; }else if(cursor != null){ - cursor = cursor.target(); + cursor = cursor.target(); cursorType = cursor.block().getCursor(cursor); @@ -187,15 +196,15 @@ public class DesktopInput extends InputHandler{ } } - if(!ui.hasMouse()) { - cursorType.set(); - } + if(!ui.hasMouse()){ + cursorType.set(); + } cursorType = normal; - } + } - @Override - public boolean touchDown (int screenX, int screenY, int pointer, int button) { + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ if(player.isDead() || state.is(State.menu) || ui.hasDialog() || ui.hasMouse()) return false; Tile cursor = tileAt(screenX, screenY); @@ -203,12 +212,12 @@ public class DesktopInput extends InputHandler{ float worldx = Graphics.world(screenX, screenY).x, worldy = Graphics.world(screenX, screenY).y; - if(button == Buttons.LEFT) { //left = begin placing - if (isPlacing()) { + if(button == Buttons.LEFT){ //left = begin placing + if(isPlacing()){ selectX = cursor.x; selectY = cursor.y; mode = placing; - } else { + }else{ //only begin shooting if there's no cursor event if(!tileTapped(cursor) && !tryTapPlayer(worldx, worldy) && player.getPlaceQueue().size == 0 && !droppingItem && !tryBeginMine(cursor) && player.getMineTile() == null){ @@ -232,7 +241,7 @@ public class DesktopInput extends InputHandler{ } @Override - public boolean touchUp (int screenX, int screenY, int pointer, int button) { + public boolean touchUp(int screenX, int screenY, int pointer, int button){ if(button == Buttons.LEFT){ player.isShooting = false; } @@ -260,8 +269,8 @@ public class DesktopInput extends InputHandler{ }else if(mode == breaking){ //touch up while breaking, break everything in selection NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursor.x, cursor.y, rotation, false, maxLength); - for(int x = 0; x <= Math.abs(result.x2 - result.x); x ++ ){ - for(int y = 0; y <= Math.abs(result.y2 - result.y); y ++){ + for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){ + for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){ int wx = selectX + x * Mathf.sign(cursor.x - selectX); int wy = selectY + y * Mathf.sign(cursor.y - selectY); @@ -278,23 +287,23 @@ public class DesktopInput extends InputHandler{ } @Override - public float getMouseX() { + public float getMouseX(){ return !controlling ? control.gdxInput().getX() : controlx; } @Override - public float getMouseY() { + public float getMouseY(){ return !controlling ? control.gdxInput().getY() : controly; } @Override - public boolean isCursorVisible() { + public boolean isCursorVisible(){ return controlling; } @Override public void updateController(){ - boolean mousemove = Gdx.input.getDeltaX() > 1 || Gdx.input.getDeltaY() > 1; + boolean mousemove = Gdx.input.getDeltaX() > 1 || Gdx.input.getDeltaY() > 1; if(KeyBinds.getSection(section).device.type == DeviceType.controller && (!mousemove || player.playerIndex > 0)){ if(player.playerIndex > 0){ @@ -312,17 +321,17 @@ public class DesktopInput extends InputHandler{ float xa = Inputs.getAxis(section, "cursor_x"); float ya = Inputs.getAxis(section, "cursor_y"); - if(Math.abs(xa) > controllerMin || Math.abs(ya) > controllerMin) { - float scl = Settings.getInt("sensitivity", 100)/100f * Unit.dp.scl(1f); - controlx += xa*baseControllerSpeed*scl; - controly -= ya*baseControllerSpeed*scl; + if(Math.abs(xa) > controllerMin || Math.abs(ya) > controllerMin){ + float scl = Settings.getInt("sensitivity", 100) / 100f * Unit.dp.scl(1f); + controlx += xa * baseControllerSpeed * scl; + controly -= ya * baseControllerSpeed * scl; controlling = true; if(player.playerIndex == 0){ Gdx.input.setCursorCatched(true); } - Inputs.getProcessor().touchDragged((int)getMouseX(), (int)getMouseY(), player.playerIndex); + Inputs.getProcessor().touchDragged((int) getMouseX(), (int) getMouseY(), player.playerIndex); } controlx = Mathf.clamp(controlx, 0, Gdx.graphics.getWidth()); diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index aff1520cbd..b3f094a889 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -33,214 +33,307 @@ import io.anuke.ucore.util.Translator; import static io.anuke.mindustry.Vars.*; public abstract class InputHandler extends InputAdapter{ - /**Used for dropping items.*/ + /** + * Used for dropping items. + */ final static float playerSelectRange = mobile ? 17f : 11f; - /**Maximum line length.*/ - final static int maxLength = 100; + /** + * Maximum line length. + */ + final static int maxLength = 100; final static Translator stackTrns = new Translator(); - /**Distance on the back from where items originate.*/ - final static float backTrns = 3f; + /** + * Distance on the back from where items originate. + */ + final static float backTrns = 3f; - public final Player player; - public final String section; - public final OverlayFragment frag = new OverlayFragment(this); + public final Player player; + public final String section; + public final OverlayFragment frag = new OverlayFragment(this); - public Recipe recipe; - public int rotation; - public boolean droppingItem; + public Recipe recipe; + public int rotation; + public boolean droppingItem; - public InputHandler(Player player){ - this.player = player; - this.section = "player_" + (player.playerIndex + 1); - Timers.run(1f, () -> frag.build(Core.scene.getRoot())); + public InputHandler(Player player){ + this.player = player; + this.section = "player_" + (player.playerIndex + 1); + Timers.run(1f, () -> frag.build(Core.scene.getRoot())); } //methods to override - public void update(){ + @Remote(targets = Loc.client, called = Loc.server, in = In.entities) + public static void dropItem(Player player, float angle){ + if(Net.server() && !player.inventory.hasItem()){ + throw new ValidateException(player, "Player cannot drop an item."); + } - } - - public float getMouseX(){ - return control.gdxInput().getX(); - } - - public float getMouseY(){ - return control.gdxInput().getY(); + ItemDrop.create(player.inventory.getItem().item, player.inventory.getItem().amount, player.x, player.y, angle); + player.inventory.clearItem(); } - public void resetCursor(){ + @Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks) + public static void transferInventory(Player player, Tile tile){ + if(Net.server() && (!player.inventory.hasItem() || player.isTransferring)){ + throw new ValidateException(player, "Player cannot transfer an item."); + } - } + threads.run(() -> { + if(player == null || tile.entity == null) return; - public boolean isCursorVisible(){ - return false; - } + player.isTransferring = true; - public void buildUI(Group group){ + ItemStack stack = player.inventory.getItem(); + int accepted = tile.block().acceptStack(stack.item, stack.amount, tile, player); - } + boolean clear = stack.amount == accepted; + int sent = Mathf.clamp(accepted / 4, 1, 8); + int removed = accepted / sent; + int[] remaining = {accepted, accepted}; - public void updateController(){ + for(int i = 0; i < sent; i++){ + boolean end = i == sent - 1; + Timers.run(i * 3, () -> { + tile.block().getStackOffset(stack.item, tile, stackTrns); - } + ItemTransfer.create(stack.item, + player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns), + new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { - public void drawOutlined(){ + tile.block().handleStack(stack.item, removed, tile, player); + remaining[1] -= removed; - } + if(end && remaining[1] > 0){ + tile.block().handleStack(stack.item, remaining[1], tile, player); + } + }); - public void drawTop(){ + stack.amount -= removed; + remaining[0] -= removed; - } + if(end){ + stack.amount -= remaining[0]; + if(clear){ + player.inventory.clearItem(); + } + player.isTransferring = false; + } + }); + } + }); + } - public boolean isDrawing(){ - return false; - } + @Remote(targets = Loc.both, called = Loc.server, forward = true, in = In.blocks) + public static void onTileTapped(Player player, Tile tile){ + if(tile == null || player == null) return; + tile.block().tapped(tile, player); + } - /**Handles tile tap events that are not platform specific.*/ - boolean tileTapped(Tile tile){ - tile = tile.target(); + public void update(){ - boolean consumed = false; - boolean showedInventory = false; + } - //check if tapped block is configurable - if(tile.block().configurable && tile.getTeam() == player.getTeam()){ - consumed = true; - if(((!frag.config.isShown() && tile.block().shouldShowConfigure(tile, player)) //if the config fragment is hidden, show - //alternatively, the current selected block can 'agree' to switch config tiles - || (frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)))) { - frag.config.showConfig(tile); - } - //otherwise... - }else if(!frag.config.hasConfigMouse()){ //make sure a configuration fragment isn't on the cursor - //then, if it's shown and the current block 'agrees' to hide, hide it. - if(frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)) { - consumed = true; - frag.config.hideConfig(); - } - } + public float getMouseX(){ + return control.gdxInput().getX(); + } - //call tapped event - if(tile.getTeam() == player.getTeam()){ - CallBlocks.onTileTapped(player, tile); - } + public float getMouseY(){ + return control.gdxInput().getY(); + } - //consume tap event if necessary - if(tile.getTeam() == player.getTeam() && tile.block().consumesTap){ - consumed = true; - }else if(tile.getTeam() == player.getTeam() && tile.block().synthetic() && tile.block().hasItems && !consumed){ - frag.inv.showFor(tile); - consumed = true; - showedInventory = true; - } + public void resetCursor(){ - if(!showedInventory){ - frag.inv.hide(); - } + } - return consumed; - } + public boolean isCursorVisible(){ + return false; + } - /**Tries to select the player to drop off items, returns true if successful.*/ - boolean tryTapPlayer(float x, float y){ - if(canTapPlayer(x, y)){ - droppingItem = true; - return true; - } - return false; - } + public void buildUI(Group group){ - boolean canTapPlayer(float x, float y){ - return Vector2.dst(x, y, player.x, player.y) <= playerSelectRange && player.inventory.hasItem(); - } + } - /**Tries to begin mining a tile, returns true if successful.*/ - boolean tryBeginMine(Tile tile){ - if(canMine(tile)){ - //if a block is clicked twice, reset it - player.setMineTile(player.getMineTile() == tile ? null : tile); - return true; - } - return false; - } + public void updateController(){ - boolean canMine(Tile tile){ - return tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower - && !tile.floor().playerUnmineable - && player.inventory.canAcceptItem(tile.floor().drops.item) - && Units.getClosestEnemy(player.getTeam(), tile.worldx(), tile.worldy(), 40f, e -> true) == null //don't being mining when an enemy is near - && tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance; - } + } - /**Returns the tile at the specified MOUSE coordinates.*/ - Tile tileAt(float x, float y){ - Vector2 vec = Graphics.world(x, y); - if(isPlacing()){ - vec.sub(recipe.result.offset(), recipe.result.offset()); - } - return world.tileWorld(vec.x, vec.y); - } + public void drawOutlined(){ - public boolean isPlacing(){ - return recipe != null; - } + } - public float mouseAngle(float x, float y){ + public void drawTop(){ + + } + + public boolean isDrawing(){ + return false; + } + + /** + * Handles tile tap events that are not platform specific. + */ + boolean tileTapped(Tile tile){ + tile = tile.target(); + + boolean consumed = false, showedInventory = false, showedConsume = false; + + //check if tapped block is configurable + if(tile.block().configurable && tile.getTeam() == player.getTeam()){ + consumed = true; + if(((!frag.config.isShown() && tile.block().shouldShowConfigure(tile, player)) //if the config fragment is hidden, show + //alternatively, the current selected block can 'agree' to switch config tiles + || (frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)))){ + frag.config.showConfig(tile); + } + //otherwise... + }else if(!frag.config.hasConfigMouse()){ //make sure a configuration fragment isn't on the cursor + //then, if it's shown and the current block 'agrees' to hide, hide it. + if(frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)){ + consumed = true; + frag.config.hideConfig(); + } + } + + //call tapped event + if(tile.getTeam() == player.getTeam()){ + CallBlocks.onTileTapped(player, tile); + } + + //consume tap event if necessary + if(tile.getTeam() == player.getTeam() && tile.block().consumesTap){ + consumed = true; + }else if(tile.getTeam() == player.getTeam() && tile.block().synthetic() && !consumed){ + if(tile.block().hasItems && tile.entity.items.total() > 0){ + frag.inv.showFor(tile); + consumed = true; + showedInventory = true; + } + + if(tile.block().consumes.hasAny()){ + frag.consume.show(tile); + consumed = true; + showedConsume = true; + } + } + + if(!showedInventory){ + frag.inv.hide(); + } + + if(!showedConsume){ + frag.consume.hide(); + } + + return consumed; + } + + /** + * Tries to select the player to drop off items, returns true if successful. + */ + boolean tryTapPlayer(float x, float y){ + if(canTapPlayer(x, y)){ + droppingItem = true; + return true; + } + return false; + } + + boolean canTapPlayer(float x, float y){ + return Vector2.dst(x, y, player.x, player.y) <= playerSelectRange && player.inventory.hasItem(); + } + + /** + * Tries to begin mining a tile, returns true if successful. + */ + boolean tryBeginMine(Tile tile){ + if(canMine(tile)){ + //if a block is clicked twice, reset it + player.setMineTile(player.getMineTile() == tile ? null : tile); + return true; + } + return false; + } + + boolean canMine(Tile tile){ + return !ui.hasMouse() + && tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower + && !tile.floor().playerUnmineable + && player.inventory.canAcceptItem(tile.floor().drops.item) + && Units.getClosestEnemy(player.getTeam(), tile.worldx(), tile.worldy(), 40f, e -> true) == null //don't being mining when an enemy is near + && tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance; + } + + /** + * Returns the tile at the specified MOUSE coordinates. + */ + Tile tileAt(float x, float y){ + Vector2 vec = Graphics.world(x, y); + if(isPlacing()){ + vec.sub(recipe.result.offset(), recipe.result.offset()); + } + return world.tileWorld(vec.x, vec.y); + } + + public boolean isPlacing(){ + return recipe != null; + } + + public float mouseAngle(float x, float y){ return Graphics.world(getMouseX(), getMouseY()).sub(x, y).angle(); } - public void remove(){ - Inputs.removeProcessor(this); - frag.remove(); + public void remove(){ + Inputs.removeProcessor(this); + frag.remove(); } - public boolean canShoot(){ - return recipe == null && !ui.hasMouse() && !onConfigurable() && !isDroppingItem(); - } - - public boolean onConfigurable(){ - return false; - } + public boolean canShoot(){ + return recipe == null && !ui.hasMouse() && !onConfigurable() && !isDroppingItem(); + } - public boolean isDroppingItem(){ - return droppingItem; - } + public boolean onConfigurable(){ + return false; + } - public void tryDropItems(Tile tile, float x, float y){ - if(!droppingItem || !player.inventory.hasItem() || canTapPlayer(x, y)){ - droppingItem = false; - return; - } + public boolean isDroppingItem(){ + return droppingItem; + } - droppingItem = false; + public void tryDropItems(Tile tile, float x, float y){ + if(!droppingItem || !player.inventory.hasItem() || canTapPlayer(x, y)){ + droppingItem = false; + return; + } - ItemStack stack = player.inventory.getItem(); + droppingItem = false; - if(tile.block().acceptStack(stack.item, stack.amount, tile, player) > 0 && tile.block().hasItems){ - CallBlocks.transferInventory(player, tile); - }else{ - CallEntity.dropItem(player.angleTo(x, y)); - } - } + ItemStack stack = player.inventory.getItem(); - public boolean cursorNear(){ - return true; - } - - public void tryPlaceBlock(int x, int y){ - if(recipe != null && validPlace(x, y, recipe.result, rotation) && cursorNear()){ - placeBlock(x, y, recipe, rotation); - } - } - - public void tryBreakBlock(int x, int y){ - if(cursorNear() && validBreak(x, y)){ - breakBlock(x, y); - } - } - - public boolean validPlace(int x, int y, Block type, int rotation){ + if(tile.block().acceptStack(stack.item, stack.amount, tile, player) > 0 && tile.block().hasItems){ + CallBlocks.transferInventory(player, tile); + }else{ + CallEntity.dropItem(player.angleTo(x, y)); + } + } + + public boolean cursorNear(){ + return true; + } + + public void tryPlaceBlock(int x, int y){ + if(recipe != null && validPlace(x, y, recipe.result, rotation) && cursorNear()){ + placeBlock(x, y, recipe, rotation); + } + } + + public void tryBreakBlock(int x, int y){ + if(cursorNear() && validBreak(x, y)){ + breakBlock(x, y); + } + } + + public boolean validPlace(int x, int y, Block type, int rotation){ for(Tile tile : state.teams.get(player.getTeam()).cores){ if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){ return Build.validPlace(player.getTeam(), x, y, type, rotation) && @@ -249,90 +342,22 @@ public abstract class InputHandler extends InputAdapter{ } return false; - } - - public boolean validBreak(int x, int y){ - return Build.validBreak(player.getTeam(), x, y); - } - - public void placeBlock(int x, int y, Recipe recipe, int rotation){ + } + + public boolean validBreak(int x, int y){ + return Build.validBreak(player.getTeam(), x, y); + } + + public void placeBlock(int x, int y, Recipe recipe, int rotation){ //todo multiplayer support player.addBuildRequest(new BuildRequest(x, y, rotation, recipe)); - } + } - public void breakBlock(int x, int y){ + public void breakBlock(int x, int y){ - //todo multiplayer support - Tile tile = world.tile(x, y).target(); - player.addBuildRequest(new BuildRequest(tile.x, tile.y)); - } - - @Remote(targets = Loc.client, called = Loc.server, in = In.entities) - public static void dropItem(Player player, float angle){ - if(Net.server() && !player.inventory.hasItem()){ - throw new ValidateException(player, "Player cannot drop an item."); - } - - ItemDrop.create(player.inventory.getItem().item, player.inventory.getItem().amount, player.x, player.y, angle); - player.inventory.clearItem(); - } - - @Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks) - public static void transferInventory(Player player, Tile tile){ - if(Net.server() && (!player.inventory.hasItem() || player.isTransferring)) { - throw new ValidateException(player, "Player cannot transfer an item."); - } - - if(player == null) return; - - player.isTransferring = true; - - ItemStack stack = player.inventory.getItem(); - int accepted = tile.block().acceptStack(stack.item, stack.amount, tile, player); - - boolean clear = stack.amount == accepted; - int sent = Mathf.clamp(accepted/4, 1, 8); - int removed = accepted/sent; - int[] remaining = {accepted, accepted}; - - for(int i = 0; i < sent; i ++){ - boolean end = i == sent-1; - Timers.run(i * 3, () -> { - tile.block().getStackOffset(stack.item, tile, stackTrns); - - ItemTransfer.create(stack.item, - player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns), - new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { - - tile.block().handleStack(stack.item, removed, tile, player); - remaining[1] -= removed; - - if(end && remaining[1] > 0) { - tile.block().handleStack(stack.item, remaining[1], tile, player); - } - }); - - stack.amount -= removed; - remaining[0] -= removed; - - if(end){ - stack.amount -= remaining[0]; - if(clear){ - player.inventory.clearItem(); - } - player.isTransferring = false; - } - }); - } - - //ItemDrop.create(player.inventory.getItem().item, player.inventory.getItem().amount, player.x, player.y, angle); - //player.inventory.clearItem(); - } - - @Remote(targets = Loc.both, called = Loc.server, forward = true, in = In.blocks) - public static void onTileTapped(Player player, Tile tile){ - if(tile == null || player == null) return; - tile.block().tapped(tile, player); - } + //todo multiplayer support + Tile tile = world.tile(x, y).target(); + player.addBuildRequest(new BuildRequest(tile.x, tile.y)); + } } diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 9a260cf94d..4fc313a31c 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -33,17 +33,17 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.scene.Group; import io.anuke.ucore.scene.builders.imagebutton; import io.anuke.ucore.scene.builders.table; +import io.anuke.ucore.scene.event.Touchable; import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.input.PlaceMode.*; public class MobileInput extends InputHandler implements GestureListener{ - private static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); - - /**Maximum speed the player can pan.*/ + /** Maximum speed the player can pan. */ private static final float maxPanSpeed = 1.3f; - /**Distance to edge of screen to start panning.*/ + private static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); + /** Distance to edge of screen to start panning. */ private final float edgePan = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(60f); //gesture data @@ -51,64 +51,64 @@ public class MobileInput extends InputHandler implements GestureListener{ private Vector2 vector = new Vector2(); private float initzoom = -1; private boolean zoomed = false; - /**Set of completed guides.*/ + /** Set of completed guides. */ private ObjectSet guides = new ObjectSet<>(); - /**Position where the player started dragging a line.*/ + /** Position where the player started dragging a line. */ private int lineStartX, lineStartY; - /**Animation scale for line.*/ + /** Animation scale for line. */ private float lineScale; - /**Animation data for crosshair.*/ + /** Animation data for crosshair. */ private float crosshairScale; private TargetTrait lastTarget; - /**List of currently selected tiles to place.*/ + /** List of currently selected tiles to place. */ private Array selection = new Array<>(); - /**Place requests to be removed.*/ + /** Place requests to be removed. */ private Array removals = new Array<>(); - /**Whether or not the player is currently shifting all placed tiles.*/ + /** Whether or not the player is currently shifting all placed tiles. */ private boolean selecting; - /**Whether the player is currently in line-place mode.*/ + /** Whether the player is currently in line-place mode. */ private boolean lineMode; - /**Current place mode.*/ + /** Current place mode. */ private PlaceMode mode = none; - /**Whether no recipe was available when switching to break mode.*/ + /** Whether no recipe was available when switching to break mode. */ private Recipe lastRecipe; - /**Last placed request. Used for drawing block overlay.*/ + /** Last placed request. Used for drawing block overlay. */ private PlaceRequest lastPlaced; - - public MobileInput(Player player){ - super(player); - Inputs.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); - } - //region utility methods + public MobileInput(Player player){ + super(player); + Inputs.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); + } - /**Check and assign targets for a specific position.*/ + //region utility methods + + /** Check and assign targets for a specific position. */ void checkTargets(float x, float y){ - synchronized (Entities.entityLock) { + synchronized(Entities.entityLock){ Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true); - if (unit != null) { + if(unit != null){ player.target = unit; - } else { + }else{ Tile tile = world.tileWorld(x, y); - if (tile != null) tile = tile.target(); + if(tile != null) tile = tile.target(); - if (tile != null && state.teams.areEnemies(player.getTeam(), tile.getTeam())) { + if(tile != null && state.teams.areEnemies(player.getTeam(), tile.getTeam())){ player.target = tile.entity; } } } } - /**Returns whether this tile is in the list of requests, or at least colliding with one.*/ - boolean hasRequest(Tile tile){ + /** Returns whether this tile is in the list of requests, or at least colliding with one. */ + boolean hasRequest(Tile tile){ return getRequest(tile) != null; } - /**Returns whether this block overlaps any selection requests.*/ + /** Returns whether this block overlaps any selection requests. */ boolean checkOverlapPlacement(int x, int y, Block block){ r2.setSize(block.size * tilesize); r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset()); @@ -125,13 +125,13 @@ public class MobileInput extends InputHandler implements GestureListener{ return true; } } - return false; + return false; } - /**Returns the selection request that overlaps this tile, or null.*/ + /** Returns the selection request that overlaps this tile, or null. */ PlaceRequest getRequest(Tile tile){ - r2.setSize(tilesize); - r2.setCenter(tile.worldx(), tile.worldy()); + r2.setSize(tilesize); + r2.setCenter(tile.worldx(), tile.worldy()); for(PlaceRequest req : selection){ Tile other = req.tile(); @@ -142,15 +142,15 @@ public class MobileInput extends InputHandler implements GestureListener{ r1.setSize(req.recipe.result.size * tilesize); r1.setCenter(other.worldx() + req.recipe.result.offset(), other.worldy() + req.recipe.result.offset()); - if (r2.overlaps(r1)) { + if(r2.overlaps(r1)){ return req; } - }else { + }else{ r1.setSize(other.block().size * tilesize); r1.setCenter(other.worldx() + other.block().offset(), other.worldy() + other.block().offset()); - if (r2.overlaps(r1)) { + if(r2.overlaps(r1)){ return req; } } @@ -166,7 +166,7 @@ public class MobileInput extends InputHandler implements GestureListener{ void drawRequest(PlaceRequest request){ Tile tile = request.tile(); - if(!request.remove) { + if(!request.remove){ //draw placing request float offset = request.recipe.result.offset(); TextureRegion[] regions = request.recipe.result.getBlockIcon(); @@ -174,7 +174,7 @@ public class MobileInput extends InputHandler implements GestureListener{ Draw.alpha(Mathf.clamp((1f - request.scale) / 0.5f)); Draw.tint(Color.WHITE, Palette.breakInvalid, request.redness); - for (TextureRegion region : regions) { + for(TextureRegion region : regions){ Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset, region.getRegionWidth() * request.scale, region.getRegionHeight() * request.scale, request.recipe.result.rotate ? request.rotation * 90 : 0); @@ -182,7 +182,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Draw.color(Palette.remove); //draw removing request - Lines.poly(tile.drawx(), tile.drawy(), 4, tile.block().size * tilesize/2f * request.scale, 45 + 15); + Lines.poly(tile.drawx(), tile.drawy(), 4, tile.block().size * tilesize / 2f * request.scale, 45 + 15); } } @@ -207,9 +207,9 @@ public class MobileInput extends InputHandler implements GestureListener{ //region UI and drawing @Override - public void buildUI(Group group) { + public void buildUI(Group group){ - //Create confirm/cancel table + //Create confirm/cancel table new table(){{ abottom().aleft(); @@ -217,6 +217,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a cancel button new imagebutton("icon-cancel", 16 * 2f, () -> { mode = none; @@ -227,12 +229,12 @@ public class MobileInput extends InputHandler implements GestureListener{ //Add an accept button, which places everything. new imagebutton("icon-check", 16 * 2f, () -> { - for (PlaceRequest request : selection) { + for(PlaceRequest request : selection){ Tile tile = request.tile(); //actually place/break all selected blocks - if (tile != null) { - if(!request.remove) { + if(tile != null){ + if(!request.remove){ rotation = request.rotation; recipe = request.recipe; tryPlaceBlock(tile.x, tile.y); @@ -264,6 +266,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a break button. new imagebutton("icon-break", "toggle", 16 * 2f, () -> { mode = mode == breaking ? recipe == null ? none : placing : breaking; @@ -278,6 +282,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a 'cancel building' button. new imagebutton("icon-cancel", 16 * 2f, player::clearBuilding); @@ -292,12 +298,12 @@ public class MobileInput extends InputHandler implements GestureListener{ } @Override - public boolean isPlacing() { + public boolean isPlacing(){ return super.isPlacing() && mode == placing; } @Override - public void drawOutlined(){ + public void drawOutlined(){ //Draw.color(Palette.placing); //Lines.poly(player.x, player.y, 100, Player.placeDistance); @@ -324,11 +330,11 @@ public class MobileInput extends InputHandler implements GestureListener{ if(tile == null) continue; - if ((!request.remove && validPlace(tile.x, tile.y, request.recipe.result, request.rotation)) - || (request.remove && validBreak(tile.x, tile.y))) { + if((!request.remove && validPlace(tile.x, tile.y, request.recipe.result, request.rotation)) + || (request.remove && validBreak(tile.x, tile.y))){ request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f); request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); - } else { + }else{ request.scale = Mathf.lerpDelta(request.scale, 0.5f, 0.1f); request.redness = Mathf.lerpDelta(request.redness, 1f, 0.2f); } @@ -353,7 +359,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(tile != null){ //draw placing - if(mode == placing && recipe != null) { + if(mode == placing && recipe != null){ NormalizeDrawResult dresult = PlaceUtils.normalizeDrawArea(recipe.result, lineStartX, lineStartY, tile.x, tile.y, true, maxLength, lineScale); Lines.rect(dresult.x, dresult.y, dresult.x2 - dresult.x, dresult.y2 - dresult.y); @@ -361,20 +367,20 @@ public class MobileInput extends InputHandler implements GestureListener{ NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tile.x, tile.y, rotation, true, maxLength); //go through each cell and draw the block to place if valid - for (int i = 0; i <= result.getLength(); i += recipe.result.size) { + for(int i = 0; i <= result.getLength(); i += recipe.result.size){ int x = lineStartX + i * Mathf.sign(tile.x - lineStartX) * Mathf.bool(result.isX()); int y = lineStartY + i * Mathf.sign(tile.y - lineStartY) * Mathf.bool(!result.isX()); - if (!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)) { + if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){ Draw.color(); TextureRegion[] regions = recipe.result.getBlockIcon(); - for (TextureRegion region : regions) { + for(TextureRegion region : regions){ Draw.rect(region, x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), region.getRegionWidth() * lineScale, region.getRegionHeight() * lineScale, recipe.result.rotate ? result.rotation * 90 : 0); } - } else { + }else{ Draw.color(Palette.breakInvalid); Lines.square(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), recipe.result.size * tilesize / 2f); } @@ -390,13 +396,13 @@ public class MobileInput extends InputHandler implements GestureListener{ Draw.alpha(0.6f); Draw.alpha(1f); - for(int x = dresult.x; x <= dresult.x2; x ++){ - for(int y = dresult.y; y <= dresult.y2; y ++){ + for(int x = dresult.x; x <= dresult.x2; x++){ + for(int y = dresult.y; y <= dresult.y2; y++){ Tile other = world.tile(x, y); if(other == null || !validBreak(other.x, other.y)) continue; other = other.target(); - Lines.poly(other.drawx(), other.drawy(), 4, other.block().size * tilesize/2f, 45 + 15); + Lines.poly(other.drawx(), other.drawy(), 4, other.block().size * tilesize / 2f, 45 + 15); } } @@ -420,8 +426,8 @@ public class MobileInput extends InputHandler implements GestureListener{ float radius = Interpolation.swingIn.apply(crosshairScale); - Lines.poly(player.target.getX(), player.target.getY(), 4, 7f * radius, Timers.time()*1.5f); - Lines.spikes(player.target.getX(), player.target.getY(), 3f * radius, 6f * radius, 4, Timers.time()*1.5f); + Lines.poly(player.target.getX(), player.target.getY(), 4, 7f * radius, Timers.time() * 1.5f); + Lines.spikes(player.target.getX(), player.target.getY(), 3f * radius, 6f * radius, 4, Timers.time() * 1.5f); } Draw.reset(); @@ -431,9 +437,9 @@ public class MobileInput extends InputHandler implements GestureListener{ //region input events - @Override - public boolean touchDown(int screenX, int screenY, int pointer, int button){ - if(state.is(State.menu)) return false; + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + if(state.is(State.menu)) return false; //get tile on cursor Tile cursor = tileAt(screenX, screenY); @@ -453,19 +459,19 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - return false; - } + return false; + } @Override public boolean touchUp(int screenX, int screenY, int pointer, int button){ //place down a line if in line mode - if(lineMode) { + if(lineMode){ Tile tile = tileAt(screenX, screenY); - if (tile == null) return false; + if(tile == null) return false; - if(mode == placing && recipe != null) { + if(mode == placing && recipe != null){ //normalize area NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tile.x, tile.y, rotation, true, 100); @@ -473,11 +479,11 @@ public class MobileInput extends InputHandler implements GestureListener{ rotation = result.rotation; //place blocks on line - for (int i = 0; i <= result.getLength(); i += recipe.result.size) { + for(int i = 0; i <= result.getLength(); i += recipe.result.size){ int x = lineStartX + i * Mathf.sign(tile.x - lineStartX) * Mathf.bool(result.isX()); int y = lineStartY + i * Mathf.sign(tile.y - lineStartY) * Mathf.bool(!result.isX()); - if (!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)) { + if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){ PlaceRequest request = new PlaceRequest(x * tilesize, y * tilesize, recipe, result.rotation); request.scale = 1f; selection.add(request); @@ -492,8 +498,8 @@ public class MobileInput extends InputHandler implements GestureListener{ NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tile.x, tile.y, rotation, false, maxLength); //break everything in area - for(int x = 0; x <= Math.abs(result.x2 - result.x); x ++ ){ - for(int y = 0; y <= Math.abs(result.y2 - result.y); y ++){ + for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){ + for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){ int wx = lineStartX + x * Mathf.sign(tile.x - lineStartX); int wy = lineStartY + y * Mathf.sign(tile.y - lineStartY); @@ -503,7 +509,7 @@ public class MobileInput extends InputHandler implements GestureListener{ tar = tar.target(); - if (!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)) { + if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){ PlaceRequest request = new PlaceRequest(tar.worldx(), tar.worldy()); request.scale = 1f; selection.add(request); @@ -516,7 +522,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Tile tile = tileAt(screenX, screenY); - if (tile == null) return false; + if(tile == null) return false; tryDropItems(tile.target(), Graphics.world(screenX, screenY).x, Graphics.world(screenX, screenY).y); } @@ -524,7 +530,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } @Override - public boolean longPress(float x, float y) { + public boolean longPress(float x, float y){ if(state.is(State.menu) || mode == none) return false; //get tile on cursor @@ -545,11 +551,11 @@ public class MobileInput extends InputHandler implements GestureListener{ Effects.effect(Fx.tapBlock, cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe.result.size); } - return false; - } + return false; + } @Override - public boolean tap(float x, float y, int count, int button) { + public boolean tap(float x, float y, int count, int button){ if(state.is(State.menu) || lineMode) return false; float worldx = Graphics.world(x, y).x, worldy = Graphics.world(x, y).y; @@ -563,12 +569,12 @@ public class MobileInput extends InputHandler implements GestureListener{ if(cursor == null || ui.hasMouse(x, y)) return false; //remove if request present - if(hasRequest(cursor)) { + if(hasRequest(cursor)){ removeRequest(getRequest(cursor)); }else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, recipe.result, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, recipe.result)){ //add to selection queue if it's a valid place position selection.add(lastPlaced = new PlaceRequest(cursor.worldx(), cursor.worldy(), recipe, rotation)); - }else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())) { + }else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){ //add to selection queue if it's a valid BREAK position cursor = cursor.target(); selection.add(new PlaceRequest(cursor.worldx(), cursor.worldy())); @@ -588,24 +594,24 @@ public class MobileInput extends InputHandler implements GestureListener{ return false; } - @Override - public void update(){ + @Override + public void update(){ //reset state when not placing - if(mode == none){ - selecting = false; - lineMode = false; - removals.addAll(selection); - selection.clear(); + if(mode == none){ + selecting = false; + lineMode = false; + removals.addAll(selection); + selection.clear(); } if(lineMode && mode == placing && recipe == null){ - lineMode = false; + lineMode = false; } //if there is no mode and there's a recipe, switch to placing if(recipe != null && mode == none){ - mode = placing; + mode = placing; } if(recipe != null){ @@ -615,13 +621,13 @@ public class MobileInput extends InputHandler implements GestureListener{ //automatically switch to placing after a new recipe is selected if(lastRecipe != recipe && mode == breaking && recipe != null){ mode = placing; - lastRecipe = recipe; + lastRecipe = recipe; } if(lineMode){ - lineScale = Mathf.lerpDelta(lineScale, 1f, 0.1f); + lineScale = Mathf.lerpDelta(lineScale, 1f, 0.1f); - //When in line mode, pan when near screen edges automatically + //When in line mode, pan when near screen edges automatically if(Gdx.input.isTouched(0) && lineMode){ float screenX = Graphics.mouse().x, screenY = Graphics.mouse().y; @@ -651,19 +657,19 @@ public class MobileInput extends InputHandler implements GestureListener{ Core.camera.position.y += vector.y; } }else{ - lineScale = 0f; + lineScale = 0f; } //remove place requests that have disappeared - for(int i = removals.size - 1; i >= 0; i --){ + for(int i = removals.size - 1; i >= 0; i--){ PlaceRequest request = removals.get(i); if(request.scale <= 0.0001f){ removals.removeIndex(i); - i --; + i--; } } - } + } @Override public boolean pan(float x, float y, float deltaX, float deltaY){ @@ -676,14 +682,14 @@ public class MobileInput extends InputHandler implements GestureListener{ float dx = deltaX * Core.camera.zoom / Core.cameraScale, dy = deltaY * Core.camera.zoom / Core.cameraScale; - if(selecting){ //pan all requests + if(selecting){ //pan all requests for(PlaceRequest req : selection){ if(req.remove) continue; //don't shift removal requests req.x += dx; req.y -= dy; } }else{ - //pan player + //pan player Core.camera.position.x -= dx; Core.camera.position.y += dy; } @@ -692,12 +698,12 @@ public class MobileInput extends InputHandler implements GestureListener{ } @Override - public boolean panStop(float x, float y, int pointer, int button) { + public boolean panStop(float x, float y, int pointer, int button){ return false; } @Override - public boolean pinch (Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) { + public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){ if(pinch1.x < 0){ pinch1.set(initialPointer1); pinch2.set(initialPointer2); @@ -727,28 +733,35 @@ public class MobileInput extends InputHandler implements GestureListener{ } @Override - public void pinchStop () { + public void pinchStop(){ initzoom = -1; pinch2.set(pinch1.set(-1, -1)); zoomed = false; } - @Override public boolean touchDown(float x, float y, int pointer, int button) { return false; } - @Override public boolean fling(float velocityX, float velocityY, int button) { return false; } + @Override + public boolean touchDown(float x, float y, int pointer, int button){ + return false; + } + + @Override + public boolean fling(float velocityX, float velocityY, int button){ + return false; + } //endregion class PlaceRequest{ - float x, y; - Recipe recipe; - int rotation; - boolean remove; + float x, y; + Recipe recipe; + int rotation; + boolean remove; - //animation variables - float scale; - float redness; + //animation variables + float scale; + float redness; - PlaceRequest(float x, float y, Recipe recipe, int rotation) { + PlaceRequest(float x, float y, Recipe recipe, int rotation){ this.x = x; this.y = y; this.recipe = recipe; @@ -756,14 +769,14 @@ public class MobileInput extends InputHandler implements GestureListener{ this.remove = false; } - PlaceRequest(float x, float y) { + PlaceRequest(float x, float y){ this.x = x; this.y = y; this.remove = true; } Tile tile(){ - return world.tileWorld(x - (recipe == null ? 0 : recipe.result.offset()), y - (recipe == null ? 0 : recipe.result.offset())); + return world.tileWorld(x - (recipe == null ? 0 : recipe.result.offset()), y - (recipe == null ? 0 : recipe.result.offset())); } } -} +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/input/PlaceUtils.java b/core/src/io/anuke/mindustry/input/PlaceUtils.java index 2d514f9506..b74b5b31a8 100644 --- a/core/src/io/anuke/mindustry/input/PlaceUtils.java +++ b/core/src/io/anuke/mindustry/input/PlaceUtils.java @@ -5,11 +5,12 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public class PlaceUtils { +public class PlaceUtils{ private static final NormalizeResult result = new NormalizeResult(); private static final NormalizeDrawResult drawResult = new NormalizeDrawResult(); - /**Normalizes a placement area and returns the result, ready to be used for drawing a rectangle. + /** + * Normalizes a placement area and returns the result, ready to be used for drawing a rectangle. * Returned x2 and y2 will always be greater than x and y. * * @param block block that will be drawn @@ -30,12 +31,12 @@ public class PlaceUtils { drawResult.x2 = result.x2 * tilesize; drawResult.y2 = result.y2 * tilesize; - drawResult.x -= block.size * scaling * tilesize/2; - drawResult.x2 += block.size * scaling * tilesize/2; + drawResult.x -= block.size * scaling * tilesize / 2; + drawResult.x2 += block.size * scaling * tilesize / 2; - drawResult.y -= block.size * scaling * tilesize/2; - drawResult.y2 += block.size * scaling * tilesize/2; + drawResult.y -= block.size * scaling * tilesize / 2; + drawResult.y2 += block.size * scaling * tilesize / 2; drawResult.x += offset; drawResult.y += offset; @@ -45,7 +46,8 @@ public class PlaceUtils { return drawResult; } - /**Normalizes a placement area and returns the result. + /** + * Normalizes a placement area and returns the result. * Returned x2 and y2 will always be greater than x and y. * * @param tilex starting X coordinate @@ -58,18 +60,18 @@ public class PlaceUtils { */ public static NormalizeResult normalizeArea(int tilex, int tiley, int endx, int endy, int rotation, boolean snap, int maxLength){ - if(snap) { - if (Math.abs(tilex - endx) > Math.abs(tiley - endy)) { + if(snap){ + if(Math.abs(tilex - endx) > Math.abs(tiley - endy)){ endy = tiley; - } else { + }else{ endx = tilex; } - if (Math.abs(endx - tilex) > maxLength) { + if(Math.abs(endx - tilex) > maxLength){ endx = Mathf.sign(endx - tilex) * maxLength + tilex; } - if (Math.abs(endy - tiley) > maxLength) { + if(Math.abs(endy - tiley) > maxLength){ endy = Mathf.sign(endy - tiley) * maxLength + tiley; } } @@ -110,7 +112,7 @@ public class PlaceUtils { return result; } - static class NormalizeDrawResult { + static class NormalizeDrawResult{ float x, y, x2, y2; } @@ -121,17 +123,23 @@ public class PlaceUtils { return Math.abs(x2 - x) > Math.abs(y2 - y); } - /**Returns length of greater edge of the selection.*/ + /** + * Returns length of greater edge of the selection. + */ int getLength(){ return Math.max(x2 - x, y2 - y); } - /**Returns the X position of a specific index along this area as a line.*/ + /** + * Returns the X position of a specific index along this area as a line. + */ int getScaledX(int i){ return x + (x2 - x > y2 - y ? i : 0); } - /**Returns the Y position of a specific index along this area as a line.*/ + /** + * Returns the Y position of a specific index along this area as a line. + */ int getScaledY(int i){ return y + (x2 - x > y2 - y ? 0 : i); } diff --git a/core/src/io/anuke/mindustry/io/BundleLoader.java b/core/src/io/anuke/mindustry/io/BundleLoader.java index 1133360838..bc97c089e5 100644 --- a/core/src/io/anuke/mindustry/io/BundleLoader.java +++ b/core/src/io/anuke/mindustry/io/BundleLoader.java @@ -3,17 +3,17 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.I18NBundle; -import io.anuke.mindustry.core.Platform; +import io.anuke.mindustry.Vars; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Settings; +import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Log; import java.util.Locale; import static io.anuke.mindustry.Vars.headless; -public class BundleLoader { - private static final boolean externalBundle = false; +public class BundleLoader{ public static void load(){ Settings.defaults("locale", "default"); @@ -27,10 +27,10 @@ public class BundleLoader { return Locale.getDefault(); }else{ Locale lastLocale; - if (loc.contains("_")) { + if(loc.contains("_")){ String[] split = loc.split("_"); lastLocale = new Locale(split[0], split[1]); - } else { + }else{ lastLocale = new Locale(loc); } @@ -40,20 +40,20 @@ public class BundleLoader { private static void loadBundle(){ I18NBundle.setExceptionOnMissingKey(false); + try{ + //try loading external bundle + FileHandle handle = Gdx.files.local("bundle"); - if(externalBundle){ - try { - FileHandle handle = Gdx.files.local("bundle"); + Locale locale = Locale.ENGLISH; + Core.bundle = I18NBundle.createBundle(handle, locale); - Locale locale = Locale.ENGLISH; - Core.bundle = I18NBundle.createBundle(handle, locale); - }catch (Exception e){ - Log.err(e); - Platform.instance.showError("Failed to find bundle!\nMake sure you have bundle.properties in the same directory\nas the jar file.\n\nIf the problem persists, try running it through the command prompt:\n" + - "Hold left-shift, then right click and select 'open command prompt here'.\nThen, type in 'java -jar mindustry.jar' without quotes."); - Gdx.app.exit(); + Log.info("NOTE: external translation bundle has been loaded."); + if(!headless){ + Timers.run(10f, () -> Vars.ui.showInfo("Note: You have successfully loaded an external translation bundle.")); } - }else{ + }catch(Throwable e){ + //no external bundle found + FileHandle handle = Gdx.files.internal("bundles/bundle"); Locale locale = getLocale(); @@ -61,5 +61,6 @@ public class BundleLoader { if(!headless) Log.info("Got locale: {0}", locale); Core.bundle = I18NBundle.createBundle(handle, locale); } + } } diff --git a/core/src/io/anuke/mindustry/io/Changelogs.java b/core/src/io/anuke/mindustry/io/Changelogs.java index c799647f1c..85d482ad00 100644 --- a/core/src/io/anuke/mindustry/io/Changelogs.java +++ b/core/src/io/anuke/mindustry/io/Changelogs.java @@ -8,7 +8,7 @@ import io.anuke.ucore.function.Consumer; import static io.anuke.mindustry.Vars.releasesURL; -public class Changelogs { +public class Changelogs{ public static void getChangelog(Consumer> success, Consumer fail){ Net.http(releasesURL, "GET", result -> { @@ -30,7 +30,7 @@ public class Changelogs { public final String name, description; public final int id, build; - public VersionInfo(String name, String description, int id, int build) { + public VersionInfo(String name, String description, int id, int build){ this.name = name; this.description = description; this.id = id; @@ -38,7 +38,7 @@ public class Changelogs { } @Override - public String toString() { + public String toString(){ return "VersionInfo{" + "name='" + name + '\'' + ", description='" + description + '\'' + diff --git a/core/src/io/anuke/mindustry/io/Map.java b/core/src/io/anuke/mindustry/io/Map.java index 1963995a4c..1959862c79 100644 --- a/core/src/io/anuke/mindustry/io/Map.java +++ b/core/src/io/anuke/mindustry/io/Map.java @@ -6,16 +6,26 @@ import io.anuke.ucore.function.Supplier; import java.io.InputStream; -public class Map { - /**Internal map name. This is the filename, without any extensions.*/ +public class Map{ + /** + * Internal map name. This is the filename, without any extensions. + */ public final String name; - /**Whether this is a custom map.*/ + /** + * Whether this is a custom map. + */ public final boolean custom; - /**Metadata. Author description, display name, etc.*/ + /** + * Metadata. Author description, display name, etc. + */ public final MapMeta meta; - /**Supplies a new input stream with the data of this map.*/ + /** + * Supplies a new input stream with the data of this map. + */ public final Supplier stream; - /**Preview texture.*/ + /** + * Preview texture. + */ public Texture texture; public Map(String name, MapMeta meta, boolean custom, Supplier streamSupplier){ diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index 4ff93932b9..5b10c9d7ed 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -18,8 +18,10 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; -/**Reads and writes map files.*/ -public class MapIO { +/** + * Reads and writes map files. + */ +public class MapIO{ private static final int version = 0; private static IntIntMap defaultBlockMap = new IntIntMap(); @@ -36,8 +38,8 @@ public class MapIO { TileDataMarker marker = data.newDataMarker(); Color color = new Color(); - for(int y = 0; y < data.height(); y ++){ - for(int x = 0; x < data.width(); x ++){ + for(int y = 0; y < data.height(); y++){ + for(int x = 0; x < data.width(); x++){ data.read(marker); Block floor = Block.getByID(marker.floor); Block wall = Block.getByID(marker.wall); @@ -45,7 +47,7 @@ public class MapIO { if(wallc == 0 && (wall.update || wall.solid || wall.breakable)) wallc = Team.all[marker.team].intColor; wallc = wallc == 0 ? ColorMapper.getBlockColor(floor) : wallc; if(marker.elevation > 0){ - float scaling = 1f + marker.elevation/8f; + float scaling = 1f + marker.elevation / 8f; color.set(wallc); color.mul(scaling, scaling, scaling, 1f); wallc = Color.rgba8888(color); @@ -62,17 +64,17 @@ public class MapIO { public static MapTileData readPixmap(Pixmap pixmap){ MapTileData data = new MapTileData(pixmap.getWidth(), pixmap.getHeight()); - for(int x = 0; x < data.width(); x ++){ - for(int y = 0; y < data.height(); y ++){ + for(int x = 0; x < data.width(); x++){ + for(int y = 0; y < data.height(); y++){ Block block = ColorMapper.getByColor(pixmap.getPixel(y, pixmap.getWidth() - 1 - x)); if(block == null){ - data.write(x, y, DataPosition.floor, (byte)Blocks.stone.id); + data.write(x, y, DataPosition.floor, (byte) Blocks.stone.id); }else{ - data.write(x, y, DataPosition.floor, (byte)block.id); + data.write(x, y, DataPosition.floor, (byte) block.id); } - data.write(x, y, DataPosition.wall, (byte)Blocks.air.id); + data.write(x, y, DataPosition.wall, (byte) Blocks.air.id); } } @@ -94,25 +96,31 @@ public class MapIO { ds.close(); } - /**Reads tile data, skipping meta.*/ - public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException { + /** + * Reads tile data, skipping meta. + */ + public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException{ MapMeta meta = readMapMeta(stream); return readTileData(stream, meta, readOnly); } - /**Does not skip meta. Call after reading meta.*/ - public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException { + /** + * Does not skip meta. Call after reading meta. + */ + public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException{ byte[] bytes = new byte[stream.available()]; stream.readFully(bytes); return new MapTileData(bytes, meta.width, meta.height, meta.blockMap, readOnly); } - /**Reads tile data, skipping meta tags.*/ + /** + * Reads tile data, skipping meta tags. + */ public static MapTileData readTileData(Map map, boolean readOnly){ - try (DataInputStream ds = new DataInputStream(map.stream.get())){ + try(DataInputStream ds = new DataInputStream(map.stream.get())){ return MapIO.readTileData(ds, readOnly); - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } } @@ -125,14 +133,14 @@ public class MapIO { byte tagAmount = stream.readByte(); - for(int i = 0; i < tagAmount; i ++){ + for(int i = 0; i < tagAmount; i++){ String name = stream.readUTF(); String value = stream.readUTF(); tags.put(name, value); } short blocks = stream.readShort(); - for(int i = 0; i < blocks; i ++){ + for(int i = 0; i < blocks; i++){ short id = stream.readShort(); String name = stream.readUTF(); Block block = Block.getByName(name); @@ -151,7 +159,7 @@ public class MapIO { public static void writeMapMeta(DataOutputStream stream, MapMeta meta) throws IOException{ stream.writeInt(meta.version); - stream.writeByte((byte)meta.tags.size); + stream.writeByte((byte) meta.tags.size); for(Entry entry : meta.tags.entries()){ stream.writeUTF(entry.key); diff --git a/core/src/io/anuke/mindustry/io/MapMeta.java b/core/src/io/anuke/mindustry/io/MapMeta.java index 7668a76933..ab554148c5 100644 --- a/core/src/io/anuke/mindustry/io/MapMeta.java +++ b/core/src/io/anuke/mindustry/io/MapMeta.java @@ -3,13 +3,13 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.utils.IntIntMap; import com.badlogic.gdx.utils.ObjectMap; -public class MapMeta { +public class MapMeta{ public final int version; public final ObjectMap tags; public final int width, height; public final IntIntMap blockMap; - public MapMeta(int version, ObjectMap tags, int width, int height, IntIntMap blockMap) { + public MapMeta(int version, ObjectMap tags, int width, int height, IntIntMap blockMap){ this.version = version; this.tags = tags; this.width = width; diff --git a/core/src/io/anuke/mindustry/io/MapTileData.java b/core/src/io/anuke/mindustry/io/MapTileData.java index b3fb92e4ab..1a2d307d40 100644 --- a/core/src/io/anuke/mindustry/io/MapTileData.java +++ b/core/src/io/anuke/mindustry/io/MapTileData.java @@ -5,13 +5,15 @@ import io.anuke.ucore.util.Bits; import java.nio.ByteBuffer; -public class MapTileData { - /**Tile size: 4 bytes.
+public class MapTileData{ + /** + * Tile size: 4 bytes.
* 0: ground tile
* 1: wall tile
* 2: rotation + team
* 3: link (x/y)
- * 4: elevation
*/ + * 4: elevation
+ */ private final static int TILE_SIZE = 5; private final ByteBuffer buffer; @@ -36,7 +38,7 @@ public class MapTileData { this.readOnly = readOnly; if(mapping != null && !readOnly){ - for(int i = 0; i < width * height; i ++){ + for(int i = 0; i < width * height; i++){ TileDataMarker marker = new TileDataMarker(); read(marker); buffer.position(i * TILE_SIZE); @@ -59,28 +61,38 @@ public class MapTileData { return height; } - /**Write a byte to a specific position.*/ + /** + * Write a byte to a specific position. + */ public void write(int x, int y, DataPosition position, byte data){ buffer.put((x + width * y) * TILE_SIZE + position.ordinal(), data); } - /**Gets a byte at a specific position.*/ + /** + * Gets a byte at a specific position. + */ public byte read(int x, int y, DataPosition position){ return buffer.get((x + width * y) * TILE_SIZE + position.ordinal()); } - /**Reads and returns the next tile data.*/ + /** + * Reads and returns the next tile data. + */ public TileDataMarker read(TileDataMarker marker){ marker.read(buffer); return marker; } - /**Writes this tile data marker.*/ + /** + * Writes this tile data marker. + */ public void write(TileDataMarker marker){ marker.write(buffer); } - /**Sets read position to the specified coordinates*/ + /** + * Sets read position to the specified coordinates + */ public void position(int x, int y){ buffer.position((x + width * y) * TILE_SIZE); } @@ -93,7 +105,7 @@ public class MapTileData { floor, wall, link, rotationTeam, elevation } - public class TileDataMarker { + public class TileDataMarker{ public byte floor, wall; public byte link; public byte rotation; @@ -110,8 +122,8 @@ public class MapTileData { team = Bits.getRightByte(rt); if(map != null){ - floor = (byte)map.get(floor, floor); - wall = (byte)map.get(wall, wall); + floor = (byte) map.get(floor, floor); + wall = (byte) map.get(wall, wall); } } diff --git a/core/src/io/anuke/mindustry/io/Maps.java b/core/src/io/anuke/mindustry/io/Maps.java index e8aa937786..92ccdbd779 100644 --- a/core/src/io/anuke/mindustry/io/Maps.java +++ b/core/src/io/anuke/mindustry/io/Maps.java @@ -17,145 +17,171 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class Maps implements Disposable{ - /**List of all built-in maps.*/ - private static final String[] defaultMapNames = {}; - /**Tile format version.*/ - private static final int version = 0; + /** + * List of all built-in maps. + */ + private static final String[] defaultMapNames = {}; + /** + * Tile format version. + */ + private static final int version = 0; - /**Maps map names to the real maps.*/ - private ObjectMap maps = new ObjectMap<>(); - /**All maps stored in an ordered array.*/ - private Array allMaps = new ThreadArray<>(); - /**Temporary array used for returning things.*/ - private Array returnArray = new ThreadArray<>(); - /**Used for storing a list of custom map names for GWT.*/ - private Array customMapNames; + /** + * Maps map names to the real maps. + */ + private ObjectMap maps = new ObjectMap<>(); + /** + * All maps stored in an ordered array. + */ + private Array allMaps = new ThreadArray<>(); + /** + * Temporary array used for returning things. + */ + private Array returnArray = new ThreadArray<>(); + /** + * Used for storing a list of custom map names for GWT. + */ + private Array customMapNames; - public Maps(){ + public Maps(){ } - /**Returns a list of all maps, including custom ones.*/ - public Array all(){ - return allMaps; - } + /** + * Returns a list of all maps, including custom ones. + */ + public Array all(){ + return allMaps; + } - /**Returns a list of only custom maps.*/ - public Array customMaps(){ - returnArray.clear(); - for(Map map : allMaps){ - if(map.custom) returnArray.add(map); - } - return returnArray; - } + /** + * Returns a list of only custom maps. + */ + public Array customMaps(){ + returnArray.clear(); + for(Map map : allMaps){ + if(map.custom) returnArray.add(map); + } + return returnArray; + } - /**Returns a list of only default maps.*/ - public Array defaultMaps(){ - returnArray.clear(); - for(Map map : allMaps){ - if(!map.custom) returnArray.add(map); - } - return returnArray; - } + /** + * Returns a list of only default maps. + */ + public Array defaultMaps(){ + returnArray.clear(); + for(Map map : allMaps){ + if(!map.custom) returnArray.add(map); + } + return returnArray; + } - /**Returns map by internal name.*/ - public Map getByName(String name){ - return maps.get(name); - } + /** + * Returns map by internal name. + */ + public Map getByName(String name){ + return maps.get(name); + } - /**Load all maps. Should be called at application start.*/ - public void load(){ - try { - for (String name : defaultMapNames) { - FileHandle file = Gdx.files.internal("maps/" + name + "." + mapExtension); - loadMap(file.nameWithoutExtension(), file::read, false); - } - }catch (IOException e){ - throw new RuntimeException(e); - } + /** + * Load all maps. Should be called at application start. + */ + public void load(){ + try{ + for(String name : defaultMapNames){ + FileHandle file = Gdx.files.internal("maps/" + name + "." + mapExtension); + loadMap(file.nameWithoutExtension(), file::read, false); + } + }catch(IOException e){ + throw new RuntimeException(e); + } - loadCustomMaps(); - } + loadCustomMaps(); + } - /**Save a map. This updates all values and stored data necessary.*/ - public void saveMap(String name, MapTileData data, ObjectMap tags){ - try { - if (!gwt) { - FileHandle file = customMapDirectory.child(name + "." + mapExtension); - MapIO.writeMap(file.write(false), tags, data); - } else { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - MapIO.writeMap(stream, tags, data); - Settings.putString("map-data-" + name, new String(Base64Coder.encode(stream.toByteArray()))); - if(!customMapNames.contains(name, false)){ - customMapNames.add(name); - Settings.putJson("custom-maps", customMapNames); - } - Settings.save(); - } + /** + * Save a map. This updates all values and stored data necessary. + */ + public void saveMap(String name, MapTileData data, ObjectMap tags){ + try{ + if(!gwt){ + FileHandle file = customMapDirectory.child(name + "." + mapExtension); + MapIO.writeMap(file.write(false), tags, data); + }else{ + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + MapIO.writeMap(stream, tags, data); + Settings.putString("map-data-" + name, new String(Base64Coder.encode(stream.toByteArray()))); + if(!customMapNames.contains(name, false)){ + customMapNames.add(name); + Settings.putJson("custom-maps", customMapNames); + } + Settings.save(); + } - if(maps.containsKey(name)){ - if(maps.get(name).texture != null) { - maps.get(name).texture.dispose(); - maps.get(name).texture = null; - } - allMaps.removeValue(maps.get(name), true); - } + if(maps.containsKey(name)){ + if(maps.get(name).texture != null){ + maps.get(name).texture.dispose(); + maps.get(name).texture = null; + } + allMaps.removeValue(maps.get(name), true); + } - Map map = new Map(name, new MapMeta(version, tags, data.width(), data.height(), null), true, getStreamFor(name)); - if (!headless){ - map.texture = new Texture(MapIO.generatePixmap(data)); - } - allMaps.add(map); + Map map = new Map(name, new MapMeta(version, tags, data.width(), data.height(), null), true, getStreamFor(name)); + if(!headless){ + map.texture = new Texture(MapIO.generatePixmap(data)); + } + allMaps.add(map); - maps.put(name, map); - }catch (IOException e){ - throw new RuntimeException(e); - } - } + maps.put(name, map); + }catch(IOException e){ + throw new RuntimeException(e); + } + } - /**Removes a map completely.*/ - public void removeMap(Map map){ - if(map.texture != null){ - map.texture.dispose(); - map.texture = null; - } + /** + * Removes a map completely. + */ + public void removeMap(Map map){ + if(map.texture != null){ + map.texture.dispose(); + map.texture = null; + } - maps.remove(map.name); - allMaps.removeValue(map, true); + maps.remove(map.name); + allMaps.removeValue(map, true); - if (!gwt) { - customMapDirectory.child(map.name + "." + mapExtension).delete(); - } else { - customMapNames.removeValue(map.name, false); - Settings.putString("map-data-" + map.name, ""); - Settings.putJson("custom-maps", customMapNames); - Settings.save(); - } - } + if(!gwt){ + customMapDirectory.child(map.name + "." + mapExtension).delete(); + }else{ + customMapNames.removeValue(map.name, false); + Settings.putString("map-data-" + map.name, ""); + Settings.putJson("custom-maps", customMapNames); + Settings.save(); + } + } - private void loadMap(String name, Supplier supplier, boolean custom) throws IOException{ - try(DataInputStream ds = new DataInputStream(supplier.get())) { + private void loadMap(String name, Supplier supplier, boolean custom) throws IOException{ + try(DataInputStream ds = new DataInputStream(supplier.get())){ MapMeta meta = MapIO.readMapMeta(ds); Map map = new Map(name, meta, custom, supplier); - if (!headless){ - map.texture = new Texture(MapIO.generatePixmap(MapIO.readTileData(ds, meta, true))); - } + if(!headless){ + map.texture = new Texture(MapIO.generatePixmap(MapIO.readTileData(ds, meta, true))); + } maps.put(map.name, map); allMaps.add(map); } - } + } - private void loadCustomMaps(){ - if(!gwt){ + private void loadCustomMaps(){ + if(!gwt){ for(FileHandle file : customMapDirectory.list()){ try{ if(file.extension().equalsIgnoreCase(mapExtension)){ loadMap(file.nameWithoutExtension(), file::read, true); } - }catch (Exception e){ + }catch(Exception e){ Log.err("Failed to load custom map file '{0}'!", file); Log.err(e); } @@ -166,10 +192,10 @@ public class Maps implements Disposable{ for(String name : customMapNames){ try{ - String data = Settings.getString("map-data-" + name); + String data = Settings.getString("map-data-" + name, ""); byte[] bytes = Base64Coder.decode(data); loadMap(name, () -> new ByteArrayInputStream(bytes), true); - }catch (Exception e){ + }catch(Exception e){ Log.err("Failed to load custom map '{0}'!", name); Log.err(e); } @@ -177,19 +203,21 @@ public class Maps implements Disposable{ } } - /**Returns an input stream supplier for a given map name.*/ + /** + * Returns an input stream supplier for a given map name. + */ private Supplier getStreamFor(String name){ - if(!gwt){ - return customMapDirectory.child(name + "." + mapExtension)::read; - }else{ - String data = Settings.getString("map-data-" + name); - byte[] bytes = Base64Coder.decode(data); - return () -> new ByteArrayInputStream(bytes); - } - } + if(!gwt){ + return customMapDirectory.child(name + "." + mapExtension)::read; + }else{ + String data = Settings.getString("map-data-" + name, ""); + byte[] bytes = Base64Coder.decode(data); + return () -> new ByteArrayInputStream(bytes); + } + } - @Override - public void dispose() { + @Override + public void dispose(){ - } + } } diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index 1a0d94bde9..4a66242dfd 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -6,7 +6,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public abstract class SaveFileVersion { +public abstract class SaveFileVersion{ public final int version; public SaveFileVersion(int version){ @@ -15,13 +15,15 @@ public abstract class SaveFileVersion { public SaveMeta getData(DataInputStream stream) throws IOException{ long time = stream.readLong(); //read last saved time + int build = stream.readInt(); byte mode = stream.readByte(); //read the gamemode String map = stream.readUTF(); //read the map int wave = stream.readInt(); //read the wave byte difficulty = stream.readByte(); //read the difficulty - return new SaveMeta(version, time, mode, map, wave, Difficulty.values()[difficulty]); + return new SaveMeta(version, time, build, mode, map, wave, Difficulty.values()[difficulty]); } public abstract void read(DataInputStream stream) throws IOException; + public abstract void write(DataOutputStream stream) throws IOException; } diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index 4b3add8272..98ed4b251c 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Base64Coder; +import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.IntMap; import io.anuke.mindustry.Vars; import io.anuke.mindustry.io.versions.Save16; @@ -15,147 +16,151 @@ import java.util.zip.InflaterInputStream; import static io.anuke.mindustry.Vars.*; public class SaveIO{ - public static final IntMap versions = new IntMap<>(); - public static final Array versionArray = Array.with( - new Save16() - ); + public static final IntArray breakingVersions = IntArray.with(47); + public static final IntMap versions = new IntMap<>(); + public static final Array versionArray = Array.with( + new Save16() + ); - static{ - for(SaveFileVersion version : versionArray){ - versions.put(version.version, version); - } - } + static{ + for(SaveFileVersion version : versionArray){ + versions.put(version.version, version); + } + } - public static void saveToSlot(int slot){ - if(gwt){ - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - write(stream); - Settings.putString("save-"+slot+"-data", new String(Base64Coder.encode(stream.toByteArray()))); - Settings.save(); - }else{ - FileHandle file = fileFor(slot); - boolean exists = file.exists(); - if(exists) file.moveTo(file.sibling(file.name() + "-backup." + file.extension())); - try { - write(fileFor(slot)); - }catch (Exception e){ - if(exists) file.sibling(file.name() + "-backup." + file.extension()).moveTo(file); - throw new RuntimeException(e); - } - } - } - - public static void loadFromSlot(int slot){ - if(gwt){ - String string = Settings.getString("save-"+slot+"-data", ""); - ByteArrayInputStream stream = new ByteArrayInputStream(Base64Coder.decode(string)); - load(stream); - }else{ - load(fileFor(slot)); - } - } + public static void saveToSlot(int slot){ + if(gwt){ + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + write(stream); + Settings.putString("save-" + slot + "-data", new String(Base64Coder.encode(stream.toByteArray()))); + Settings.save(); + }else{ + FileHandle file = fileFor(slot); + boolean exists = file.exists(); + if(exists) file.moveTo(file.sibling(file.name() + "-backup." + file.extension())); + try{ + write(fileFor(slot)); + }catch(Exception e){ + if(exists) file.sibling(file.name() + "-backup." + file.extension()).moveTo(file); + throw new RuntimeException(e); + } + } + } - public static DataInputStream getSlotStream(int slot){ - if(gwt){ - String string = Settings.getString("save-"+slot+"-data", ""); - byte[] bytes = Base64Coder.decode(string); - return new DataInputStream(new ByteArrayInputStream(bytes)); - }else{ - return new DataInputStream(new InflaterInputStream(fileFor(slot).read())); - } - } - - public static boolean isSaveValid(int slot){ - try { - return isSaveValid(getSlotStream(slot)); - }catch (Exception e){ - return false; - } - } + public static void loadFromSlot(int slot){ + if(gwt){ + String string = Settings.getString("save-" + slot + "-data", ""); + ByteArrayInputStream stream = new ByteArrayInputStream(Base64Coder.decode(string)); + load(stream); + }else{ + load(fileFor(slot)); + } + } - public static boolean isSaveValid(FileHandle file){ - return isSaveValid(new DataInputStream(file.read())); - } + public static DataInputStream getSlotStream(int slot){ + if(gwt){ + String string = Settings.getString("save-" + slot + "-data", ""); + byte[] bytes = Base64Coder.decode(string); + return new DataInputStream(new ByteArrayInputStream(bytes)); + }else{ + return new DataInputStream(new InflaterInputStream(fileFor(slot).read())); + } + } - public static boolean isSaveValid(DataInputStream stream){ + public static boolean isSaveValid(int slot){ + try{ + return isSaveValid(getSlotStream(slot)); + }catch(Exception e){ + return false; + } + } - try{ - int version = stream.readInt(); - SaveFileVersion ver = versions.get(version); - ver.getData(stream); - return true; - }catch (Exception e){ - return false; - } - } + public static boolean isSaveValid(FileHandle file){ + return isSaveValid(new DataInputStream(new InflaterInputStream(file.read()))); + } - public static SaveMeta getData(int slot){ - return getData(getSlotStream(slot)); - } - - public static SaveMeta getData(DataInputStream stream){ - - try{ - int version = stream.readInt(); - SaveMeta meta = versions.get(version).getData(stream); - stream.close(); - return meta; - }catch (IOException e){ - throw new RuntimeException(e); - } - } - - public static FileHandle fileFor(int slot){ - return saveDirectory.child(slot + "." + Vars.saveExtension); - } + public static boolean isSaveValid(DataInputStream stream){ - public static void write(FileHandle file){ - write(file.write(false)); - } + try{ + int version = stream.readInt(); + SaveFileVersion ver = versions.get(version); + ver.getData(stream); + return true; + }catch(Exception e){ + e.printStackTrace(); + return false; + } + } - public static void write(OutputStream os){ - DataOutputStream stream; - - try{ - stream = new DataOutputStream(new DeflaterOutputStream(os)); - getVersion().write(stream); - stream.close(); - }catch (Exception e){ - throw new RuntimeException(e); - } - } + public static SaveMeta getData(int slot){ + return getData(getSlotStream(slot)); + } - public static void load(FileHandle file){ - try { - load(new InflaterInputStream(file.read())); - }catch (RuntimeException e){ - e.printStackTrace(); - FileHandle backup = file.sibling(file.name() + "-backup." + file.extension()); - if(backup.exists()){ - load(new InflaterInputStream(backup.read())); - } - } - } + public static SaveMeta getData(DataInputStream stream){ - public static void load(InputStream is){ - logic.reset(); + try{ + int version = stream.readInt(); + SaveMeta meta = versions.get(version).getData(stream); + stream.close(); + return meta; + }catch(IOException e){ + throw new RuntimeException(e); + } + } - DataInputStream stream; - - try{ - stream = new DataInputStream(is); - int version = stream.readInt(); - SaveFileVersion ver = versions.get(version); + public static FileHandle fileFor(int slot){ + return saveDirectory.child(slot + "." + Vars.saveExtension); + } - ver.read(stream); + public static void write(FileHandle file){ + write(file.write(false)); + } - stream.close(); - }catch (Exception e){ - throw new RuntimeException(e); - } - } + public static void write(OutputStream os){ + DataOutputStream stream; - public static SaveFileVersion getVersion(){ - return versionArray.peek(); - } + try{ + stream = new DataOutputStream(new DeflaterOutputStream(os)); + getVersion().write(stream); + stream.close(); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + public static void load(FileHandle file){ + try{ + load(new InflaterInputStream(file.read())); + }catch(RuntimeException e){ + e.printStackTrace(); + FileHandle backup = file.sibling(file.name() + "-backup." + file.extension()); + if(backup.exists()){ + load(new InflaterInputStream(backup.read())); + }else{ + throw new RuntimeException(e); + } + } + } + + public static void load(InputStream is){ + logic.reset(); + + DataInputStream stream; + + try{ + stream = new DataInputStream(is); + int version = stream.readInt(); + SaveFileVersion ver = versions.get(version); + + ver.read(stream); + + stream.close(); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + public static SaveFileVersion getVersion(){ + return versionArray.peek(); + } } diff --git a/core/src/io/anuke/mindustry/io/SaveMeta.java b/core/src/io/anuke/mindustry/io/SaveMeta.java index f241f8870e..f782e74db1 100644 --- a/core/src/io/anuke/mindustry/io/SaveMeta.java +++ b/core/src/io/anuke/mindustry/io/SaveMeta.java @@ -8,16 +8,18 @@ import java.util.Date; import static io.anuke.mindustry.Vars.world; -public class SaveMeta { +public class SaveMeta{ public int version; + public int build; public String date; public GameMode mode; public Map map; public int wave; public Difficulty difficulty; - public SaveMeta(int version, long date, int mode, String map, int wave, Difficulty difficulty){ + public SaveMeta(int version, long date, int build, int mode, String map, int wave, Difficulty difficulty){ this.version = version; + this.build = build; this.date = Platform.instance.format(new Date(date)); this.mode = GameMode.values()[mode]; this.map = world.maps().getByName(map); diff --git a/core/src/io/anuke/mindustry/io/Saves.java b/core/src/io/anuke/mindustry/io/Saves.java index 2ed06d4739..0fd1792034 100644 --- a/core/src/io/anuke/mindustry/io/Saves.java +++ b/core/src/io/anuke/mindustry/io/Saves.java @@ -2,10 +2,11 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.async.AsyncExecutor; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.game.Difficulty; +import io.anuke.mindustry.game.EventType.StateChangeEvent; import io.anuke.mindustry.game.GameMode; +import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.ThreadArray; @@ -14,18 +15,24 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class Saves { +public class Saves{ private int nextSlot; private Array saves = new ThreadArray<>(); private SaveSlot current; private boolean saving; private float time; - private AsyncExecutor exec = new AsyncExecutor(1); + public Saves(){ + Events.on(StateChangeEvent.class, (prev, state) -> { + if(state == State.menu){ + threads.run(() -> current = null); + } + }); + } public void load(){ saves.clear(); - for(int i = 0; i < saveSlots; i ++){ + for(int i = 0; i < saveSlots; i++){ if(SaveIO.isSaveValid(i)){ SaveSlot slot = new SaveSlot(i); saves.add(slot); @@ -35,25 +42,22 @@ public class Saves { } } - public SaveSlot getCurrent() { + public SaveSlot getCurrent(){ return current; } public void update(){ - if(state.is(State.menu)){ - current = null; - } if(!state.is(State.menu) && !state.gameOver && current != null && current.isAutosave()){ time += Timers.delta(); - if(time > Settings.getInt("saveinterval")*60) { + if(time > Settings.getInt("saveinterval") * 60){ saving = true; Timers.run(2f, () -> { - try { + try{ SaveIO.saveToSlot(current.index); current.meta = SaveIO.getData(current.index); - }catch (Exception e){ + }catch(Exception e){ e.printStackTrace(); } saving = false; @@ -80,7 +84,7 @@ public class Saves { public void addSave(String name){ SaveSlot slot = new SaveSlot(nextSlot); - nextSlot ++; + nextSlot++; slot.setName(name); saves.add(slot); SaveIO.saveToSlot(slot.index); @@ -91,7 +95,7 @@ public class Saves { public SaveSlot importSave(FileHandle file) throws IOException{ SaveSlot slot = new SaveSlot(nextSlot); slot.importFile(file); - nextSlot ++; + nextSlot++; slot.setName(file.nameWithoutExtension()); saves.add(slot); slot.meta = SaveIO.getData(slot.index); @@ -112,15 +116,15 @@ public class Saves { } public void load(){ - current = this; SaveIO.loadFromSlot(index); meta = SaveIO.getData(index); + current = this; } public void save(){ - current = this; SaveIO.saveToSlot(index); meta = SaveIO.getData(index); + current = this; } public String getDate(){ @@ -132,14 +136,18 @@ public class Saves { } public String getName(){ - return Settings.getString("save-"+index+"-name", "untittled"); + return Settings.getString("save-" + index + "-name", "untittled"); } public void setName(String name){ - Settings.putString("save-"+index+"-name", name); + Settings.putString("save-" + index + "-name", name); Settings.save(); } + public int getBuild(){ + return meta.build; + } + public int getWave(){ return meta.wave; } @@ -153,18 +161,18 @@ public class Saves { } public boolean isAutosave(){ - return Settings.getBool("save-"+index+"-autosave", !gwt); + return Settings.getBool("save-" + index + "-autosave", !gwt); } public void setAutosave(boolean save){ - Settings.putBool("save-"+index + "-autosave", save); + Settings.putBool("save-" + index + "-autosave", save); Settings.save(); } public void importFile(FileHandle file) throws IOException{ try{ file.copyTo(SaveIO.fileFor(index)); - }catch (Exception e){ + }catch(Exception e){ throw new IOException(e); } } @@ -175,7 +183,7 @@ public class Saves { file = file.parent().child(file.nameWithoutExtension() + "." + saveExtension); } SaveIO.fileFor(index).copyTo(file); - }catch (Exception e){ + }catch(Exception e){ throw new IOException(e); } } diff --git a/core/src/io/anuke/mindustry/io/TypeIO.java b/core/src/io/anuke/mindustry/io/TypeIO.java index ec7bab7a8c..34475643ea 100644 --- a/core/src/io/anuke/mindustry/io/TypeIO.java +++ b/core/src/io/anuke/mindustry/io/TypeIO.java @@ -27,14 +27,16 @@ import java.nio.ByteBuffer; import static io.anuke.mindustry.Vars.*; -/**Class for specifying read/write methods for code generation.*/ -public class TypeIO { +/** + * Class for specifying read/write methods for code generation. + */ +public class TypeIO{ @WriteClass(Player.class) public static void writePlayer(ByteBuffer buffer, Player player){ if(player == null){ buffer.putInt(-1); - }else { + }else{ buffer.putInt(player.id); } } @@ -47,7 +49,7 @@ public class TypeIO { @WriteClass(Unit.class) public static void writeUnit(ByteBuffer buffer, Unit unit){ - buffer.put((byte)unit.getGroup().getID()); + buffer.put((byte) unit.getGroup().getID()); buffer.putInt(unit.getID()); } @@ -55,12 +57,12 @@ public class TypeIO { public static Unit readUnit(ByteBuffer buffer){ byte gid = buffer.get(); int id = buffer.getInt(); - return (Unit)Entities.getGroup(gid).getByID(id); + return (Unit) Entities.getGroup(gid).getByID(id); } @WriteClass(ShooterTrait.class) public static void writeShooter(ByteBuffer buffer, ShooterTrait trait){ - buffer.put((byte)trait.getGroup().getID()); + buffer.put((byte) trait.getGroup().getID()); buffer.putInt(trait.getID()); } @@ -85,10 +87,10 @@ public class TypeIO { @WriteClass(CarriableTrait.class) public static void writeCarriable(ByteBuffer buffer, CarriableTrait unit){ if(unit == null){ - buffer.put((byte)-1); + buffer.put((byte) -1); return; } - buffer.put((byte)unit.getGroup().getID()); + buffer.put((byte) unit.getGroup().getID()); buffer.putInt(unit.getID()); } @@ -99,15 +101,16 @@ public class TypeIO { return null; } int id = buffer.getInt(); - return (CarriableTrait)Entities.getGroup(gid).getByID(id); + return (CarriableTrait) Entities.getGroup(gid).getByID(id); } @WriteClass(CarryTrait.class) public static void writeCarry(ByteBuffer buffer, CarryTrait unit){ if(unit == null){ - buffer.put((byte)-1); + buffer.put((byte) -1); + return; } - buffer.put((byte)unit.getGroup().getID()); + buffer.put((byte) unit.getGroup().getID()); buffer.putInt(unit.getID()); } @@ -118,12 +121,12 @@ public class TypeIO { return null; } int id = buffer.getInt(); - return (CarryTrait)Entities.getGroup(gid).getByID(id); + return (CarryTrait) Entities.getGroup(gid).getByID(id); } @WriteClass(BaseUnit.class) public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte)unit.getGroup().getID()); + buffer.put((byte) unitGroups[unit.getTeam().ordinal()].getID()); buffer.putInt(unit.getID()); } @@ -131,7 +134,7 @@ public class TypeIO { public static BaseUnit writeBaseUnit(ByteBuffer buffer){ byte gid = buffer.get(); int id = buffer.getInt(); - return (BaseUnit)Entities.getGroup(gid).getByID(id); + return (BaseUnit) Entities.getGroup(gid).getByID(id); } @WriteClass(Tile.class) @@ -146,7 +149,7 @@ public class TypeIO { @WriteClass(Block.class) public static void writeBlock(ByteBuffer buffer, Block block){ - buffer.put((byte)block.id); + buffer.put((byte) block.id); } @ReadClass(Block.class) @@ -156,7 +159,7 @@ public class TypeIO { @WriteClass(KickReason.class) public static void writeKick(ByteBuffer buffer, KickReason reason){ - buffer.put((byte)reason.ordinal()); + buffer.put((byte) reason.ordinal()); } @ReadClass(KickReason.class) @@ -166,7 +169,7 @@ public class TypeIO { @WriteClass(Team.class) public static void writeTeam(ByteBuffer buffer, Team reason){ - buffer.put((byte)reason.ordinal()); + buffer.put((byte) reason.ordinal()); } @ReadClass(Team.class) @@ -176,7 +179,7 @@ public class TypeIO { @WriteClass(AdminAction.class) public static void writeAction(ByteBuffer buffer, AdminAction reason){ - buffer.put((byte)reason.ordinal()); + buffer.put((byte) reason.ordinal()); } @ReadClass(AdminAction.class) @@ -186,7 +189,7 @@ public class TypeIO { @WriteClass(Effect.class) public static void writeEffect(ByteBuffer buffer, Effect effect){ - buffer.putShort((short)effect.id); + buffer.putShort((short) effect.id); } @ReadClass(Effect.class) @@ -226,7 +229,7 @@ public class TypeIO { @WriteClass(Liquid.class) public static void writeLiquid(ByteBuffer buffer, Liquid liquid){ - buffer.put((byte)liquid.id); + buffer.put((byte) liquid.id); } @ReadClass(Liquid.class) @@ -246,7 +249,7 @@ public class TypeIO { @WriteClass(BulletType.class) public static void writeBulletType(ByteBuffer buffer, BulletType type){ - buffer.put((byte)type.id); + buffer.put((byte) type.id); } @ReadClass(BulletType.class) @@ -256,7 +259,7 @@ public class TypeIO { @WriteClass(Item.class) public static void writeItem(ByteBuffer buffer, Item item){ - buffer.put((byte)item.id); + buffer.put((byte) item.id); } @ReadClass(Item.class) @@ -266,7 +269,7 @@ public class TypeIO { @WriteClass(Recipe.class) public static void writeRecipe(ByteBuffer buffer, Recipe recipe){ - buffer.put((byte)recipe.id); + buffer.put((byte) recipe.id); } @ReadClass(Recipe.class) @@ -276,19 +279,19 @@ public class TypeIO { @WriteClass(String.class) public static void writeString(ByteBuffer buffer, String string){ - if(string != null) { + if(string != null){ byte[] bytes = string.getBytes(); buffer.putShort((short) bytes.length); buffer.put(bytes); }else{ - buffer.putShort((short)-1); + buffer.putShort((short) -1); } } @ReadClass(String.class) public static String readString(ByteBuffer buffer){ short length = buffer.getShort(); - if(length != -1) { + if(length != -1){ byte[] bytes = new byte[length]; buffer.get(bytes); return new String(bytes); @@ -299,7 +302,7 @@ public class TypeIO { @WriteClass(byte[].class) public static void writeBytes(ByteBuffer buffer, byte[] bytes){ - buffer.putShort((short)bytes.length); + buffer.putShort((short) bytes.length); buffer.put(bytes); } @@ -314,10 +317,10 @@ public class TypeIO { @WriteClass(TraceInfo.class) public static void writeTrace(ByteBuffer buffer, TraceInfo info){ buffer.putInt(info.playerid); - buffer.putShort((short)info.ip.getBytes().length); + buffer.putShort((short) info.ip.getBytes().length); buffer.put(info.ip.getBytes()); - buffer.put(info.modclient ? (byte)1 : 0); - buffer.put(info.android ? (byte)1 : 0); + buffer.put(info.modclient ? (byte) 1 : 0); + buffer.put(info.android ? (byte) 1 : 0); buffer.putInt(info.totalBlocksBroken); buffer.putInt(info.structureBlocksBroken); diff --git a/core/src/io/anuke/mindustry/io/Version.java b/core/src/io/anuke/mindustry/io/Version.java index 473d266b0d..8bd816fb89 100644 --- a/core/src/io/anuke/mindustry/io/Version.java +++ b/core/src/io/anuke/mindustry/io/Version.java @@ -8,15 +8,15 @@ import io.anuke.ucore.util.Strings; import java.io.IOException; -public class Version { +public class Version{ public static String name; public static String type; public static String code; - public static int build; + public static int build = 0; public static String buildName; public static void init(){ - try { + try{ FileHandle file = Gdx.files.internal("version.properties"); ObjectMap map = new ObjectMap<>(); @@ -28,7 +28,7 @@ public class Version { build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1; buildName = build == -1 ? map.get("build") : "build " + build; - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } } diff --git a/core/src/io/anuke/mindustry/io/versions/Save16.java b/core/src/io/anuke/mindustry/io/versions/Save16.java index 263ff28e06..afe056970c 100644 --- a/core/src/io/anuke/mindustry/io/versions/Save16.java +++ b/core/src/io/anuke/mindustry/io/versions/Save16.java @@ -11,6 +11,7 @@ import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.Map; import io.anuke.mindustry.io.SaveFileVersion; +import io.anuke.mindustry.io.Version; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.BlockPart; @@ -27,14 +28,14 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; -public class Save16 extends SaveFileVersion { +public class Save16 extends SaveFileVersion{ public Save16(){ super(16); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ /*long loadTime = */ stream.readLong(); @@ -61,7 +62,7 @@ public class Save16 extends SaveFileVersion { IntMap blockMap = new IntMap<>(); - for(int i = 0; i < blocksize; i ++){ + for(int i = 0; i < blocksize; i++){ String name = stream.readUTF(); int id = stream.readShort(); @@ -72,9 +73,9 @@ public class Save16 extends SaveFileVersion { byte groups = stream.readByte(); - for (int i = 0; i < groups; i++) { + for(int i = 0; i < groups; i++){ int amount = stream.readInt(); - for (int j = 0; j < amount; j++) { + for(int j = 0; j < amount; j++){ byte typeid = stream.readByte(); SaveTrait trait = (SaveTrait) TypeTrait.getTypeByID(typeid).get(); trait.readSave(stream); @@ -94,8 +95,8 @@ public class Save16 extends SaveFileVersion { Tile[][] tiles = world.createTiles(width, height); - for (int i = 0; i < width * height; i++) { - int x = i % width, y = i /width; + for(int i = 0; i < width * height; i++){ + int x = i % width, y = i / width; byte floorid = stream.readByte(); byte wallid = stream.readByte(); byte elevation = stream.readByte(); @@ -103,9 +104,9 @@ public class Save16 extends SaveFileVersion { Tile tile = new Tile(x, y, floorid, wallid); tile.elevation = elevation; - if (wallid == Blocks.blockpart.id) { + if(wallid == Blocks.blockpart.id){ tile.link = stream.readByte(); - }else if (tile.entity != null) { + }else if(tile.entity != null){ byte tr = stream.readByte(); short health = stream.readShort(); @@ -118,9 +119,10 @@ public class Save16 extends SaveFileVersion { tile.entity.health = health; tile.setRotation(rotation); - if (tile.entity.items != null) tile.entity.items.read(stream); - if (tile.entity.power != null) tile.entity.power.read(stream); - if (tile.entity.liquids != null) tile.entity.liquids.read(stream); + if(tile.entity.items != null) tile.entity.items.read(stream); + if(tile.entity.power != null) tile.entity.power.read(stream); + if(tile.entity.liquids != null) tile.entity.liquids.read(stream); + if(tile.entity.cons != null) tile.entity.cons.read(stream); tile.entity.read(stream); @@ -131,7 +133,7 @@ public class Save16 extends SaveFileVersion { }else if(wallid == 0){ int consecutives = stream.readUnsignedByte(); - for (int j = i + 1; j < i + 1 + consecutives; j++) { + for(int j = i + 1; j < i + 1 + consecutives; j++){ int newx = j % width, newy = j / width; Tile newTile = new Tile(newx, newy, floorid, wallid); newTile.elevation = elevation; @@ -148,10 +150,11 @@ public class Save16 extends SaveFileVersion { } @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ //--META-- stream.writeInt(version); //version id stream.writeLong(TimeUtils.millis()); //last saved + stream.writeInt(Version.build); //--GENERAL STATE-- stream.writeByte(state.mode.ordinal()); //gamemode @@ -167,20 +170,19 @@ public class Save16 extends SaveFileVersion { stream.writeInt(Block.all().size); - for(int i = 0; i < Block.all().size; i ++){ + for(int i = 0; i < Block.all().size; i++){ Block block = Block.all().get(i); stream.writeUTF(block.name); stream.writeShort(block.id); } //--ENTITIES-- - //TODO synchronized block here int groups = 0; for(EntityGroup group : Entities.getAllGroups()){ if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){ - groups ++; + groups++; } } @@ -190,8 +192,8 @@ public class Save16 extends SaveFileVersion { if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){ stream.writeInt(group.size()); for(Entity entity : group.all()){ - stream.writeByte(((SaveTrait)entity).getTypeID()); - ((SaveTrait)entity).writeSave(stream); + stream.writeByte(((SaveTrait) entity).getTypeID()); + ((SaveTrait) entity).writeSave(stream); } } } @@ -204,7 +206,7 @@ public class Save16 extends SaveFileVersion { stream.writeShort(world.width()); stream.writeShort(world.height()); - for (int i = 0; i < world.width() * world.height(); i++) { + for(int i = 0; i < world.width() * world.height(); i++){ Tile tile = world.tile(i); stream.writeByte(tile.getFloorID()); @@ -215,24 +217,25 @@ public class Save16 extends SaveFileVersion { stream.writeByte(tile.link); }else if(tile.entity != null){ stream.writeByte(Bits.packByte(tile.getTeamID(), tile.getRotation())); //team + rotation - stream.writeShort((short)tile.entity.health); //health + stream.writeShort((short) tile.entity.health); //health if(tile.entity.items != null) tile.entity.items.write(stream); if(tile.entity.power != null) tile.entity.power.write(stream); if(tile.entity.liquids != null) tile.entity.liquids.write(stream); + if(tile.entity.cons != null) tile.entity.cons.write(stream); tile.entity.write(stream); }else if(tile.getWallID() == 0){ int consecutives = 0; - for (int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++) { + for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ Tile nextTile = world.tile(j); if(nextTile.getFloorID() != tile.getFloorID() || nextTile.getWallID() != 0 || nextTile.elevation != tile.elevation){ break; } - consecutives ++; + consecutives++; } stream.writeByte(consecutives); diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index c63f628c2b..bb838d4afd 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -15,24 +15,30 @@ import io.anuke.ucore.core.Settings; import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.world; -public class Administration { +public class Administration{ public static final int defaultMaxBrokenBlocks = 15; - public static final int defaultBreakCooldown = 1000*15; + public static final int defaultBreakCooldown = 1000 * 15; - /**All player info. Maps UUIDs to info. This persists throughout restarts.*/ + /** + * All player info. Maps UUIDs to info. This persists throughout restarts. + */ private ObjectMap playerInfo = new ObjectMap<>(); - /**Maps UUIDs to trace infos. This is wiped when a player logs off.*/ + /** + * Maps UUIDs to trace infos. This is wiped when a player logs off. + */ private ObjectMap traceInfo = new ObjectMap<>(); - /**Maps packed coordinates to logs for that coordinate */ + /** + * Maps packed coordinates to logs for that coordinate + */ private IntMap> editLogs = new IntMap<>(); private Array bannedIPs = new Array<>(); public Administration(){ Settings.defaultList( - "antigrief", false, - "antigrief-max", defaultMaxBrokenBlocks, - "antigrief-cooldown", defaultBreakCooldown + "antigrief", false, + "antigrief-max", defaultMaxBrokenBlocks, + "antigrief-cooldown", defaultBreakCooldown ); load(); @@ -42,6 +48,11 @@ public class Administration { return Settings.getBool("antigrief"); } + public void setAntiGrief(boolean antiGrief){ + Settings.putBool("antigrief", antiGrief); + Settings.save(); + } + public boolean allowsCustomClients(){ return Settings.getBool("allow-custom", !headless); } @@ -55,31 +66,26 @@ public class Administration { return false; } - public void setAntiGrief(boolean antiGrief){ - Settings.putBool("antigrief", antiGrief); - Settings.save(); - } - public void setAntiGriefParams(int maxBreak, int cooldown){ Settings.putInt("antigrief-max", maxBreak); Settings.putInt("antigrief-cooldown", cooldown); Settings.save(); } - public IntMap> getEditLogs() { + public IntMap> getEditLogs(){ return editLogs; } - public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action) { - if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) return; - if(editLogs.containsKey(x + y * world.width())) { - editLogs.get(x + y * world.width()).add(new EditLog(player.name, block, rotation, action)); - } - else { - Array logs = new Array<>(); - logs.add(new EditLog(player.name, block, rotation, action)); - editLogs.put(x + y * world.width(), logs); - } + public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action){ + if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) + return; + if(editLogs.containsKey(x + y * world.width())){ + editLogs.get(x + y * world.width()).add(new EditLog(player.name, block, rotation, action)); + }else{ + Array logs = new Array<>(); + logs.add(new EditLog(player.name, block, rotation, action)); + editLogs.put(x + y * world.width(), logs); + } } /* @@ -143,18 +149,18 @@ public class Administration { long[] breaks = info.lastBroken; int shiftBy = 0; - for(int i = 0; i < breaks.length && breaks[i] != 0; i ++){ + for(int i = 0; i < breaks.length && breaks[i] != 0; i++){ if(TimeUtils.timeSinceMillis(breaks[i]) >= Settings.getInt("antigrief-cooldown")){ shiftBy = i; } } - for (int i = 0; i < breaks.length; i++) { + for(int i = 0; i < breaks.length; i++){ breaks[i] = (i + shiftBy >= breaks.length) ? 0 : breaks[i + shiftBy]; } int remaining = 0; - for(int i = 0; i < breaks.length; i ++){ + for(int i = 0; i < breaks.length; i++){ if(breaks[i] == 0){ remaining = breaks.length - i; break; @@ -167,17 +173,21 @@ public class Administration { return true; } - /**Call when a player joins to update their information here.*/ + /** + * Call when a player joins to update their information here. + */ public void updatePlayerJoined(String id, String ip, String name){ PlayerInfo info = getCreateInfo(id); info.lastName = name; info.lastIP = ip; - info.timesJoined ++; + info.timesJoined++; if(!info.names.contains(name, false)) info.names.add(name); if(!info.ips.contains(ip, false)) info.ips.add(ip); } - /**Returns trace info by IP.*/ + /** + * Returns trace info by IP. + */ public TraceInfo getTraceByID(String uuid){ if(!traceInfo.containsKey(uuid)) traceInfo.put(uuid, new TraceInfo(uuid)); @@ -188,8 +198,10 @@ public class Administration { traceInfo.clear(); } - /**Bans a player by IP; returns whether this player was already banned. - * If there are players who at any point had this IP, they will be UUID banned as well.*/ + /** + * Bans a player by IP; returns whether this player was already banned. + * If there are players who at any point had this IP, they will be UUID banned as well. + */ public boolean banPlayerIP(String ip){ if(bannedIPs.contains(ip, false)) return false; @@ -206,7 +218,9 @@ public class Administration { return true; } - /**Bans a player by UUID; returns whether this player was already banned.*/ + /** + * Bans a player by UUID; returns whether this player was already banned. + */ public boolean banPlayerID(String id){ if(playerInfo.containsKey(id) && playerInfo.get(id).banned) return false; @@ -218,8 +232,10 @@ public class Administration { return true; } - /**Unbans a player by IP; returns whether this player was banned in the first place. - * This method also unbans any player that was banned and had this IP.*/ + /** + * Unbans a player by IP; returns whether this player was banned in the first place. + * This method also unbans any player that was banned and had this IP. + */ public boolean unbanPlayerIP(String ip){ boolean found = bannedIPs.contains(ip, false); @@ -237,8 +253,10 @@ public class Administration { return found; } - /**Unbans a player by ID; returns whether this player was banned in the first place. - * This also unbans all IPs the player used.*/ + /** + * Unbans a player by ID; returns whether this player was banned in the first place. + * This also unbans all IPs the player used. + */ public boolean unbanPlayerID(String id){ PlayerInfo info = getCreateInfo(id); @@ -252,7 +270,9 @@ public class Administration { return true; } - /**Returns list of all players with admin status*/ + /** + * Returns list of all players with admin status + */ public Array getAdmins(){ Array result = new Array<>(); for(PlayerInfo info : playerInfo.values()){ @@ -263,7 +283,9 @@ public class Administration { return result; } - /**Returns list of all players with admin status*/ + /** + * Returns list of all players with admin status + */ public Array getBanned(){ Array result = new Array<>(); for(PlayerInfo info : playerInfo.values()){ @@ -274,12 +296,16 @@ public class Administration { return result; } - /**Returns all banned IPs. This does not include the IPs of ID-banned players.*/ + /** + * Returns all banned IPs. This does not include the IPs of ID-banned players. + */ public Array getBannedIPs(){ return bannedIPs; } - /**Makes a player an admin. Returns whether this player was already an admin.*/ + /** + * Makes a player an admin. Returns whether this player was already an admin. + */ public boolean adminPlayer(String id, String usid){ PlayerInfo info = getCreateInfo(id); @@ -293,7 +319,9 @@ public class Administration { return true; } - /**Makes a player no longer an admin. Returns whether this player was an admin in the first place.*/ + /** + * Makes a player no longer an admin. Returns whether this player was an admin in the first place. + */ public boolean unAdminPlayer(String id){ PlayerInfo info = getCreateInfo(id); @@ -401,7 +429,8 @@ public class Administration { this.id = id; } - private PlayerInfo(){} + private PlayerInfo(){ + } } } diff --git a/core/src/io/anuke/mindustry/net/EditLog.java b/core/src/io/anuke/mindustry/net/EditLog.java index 33d1eb42e1..ab922ae8e0 100644 --- a/core/src/io/anuke/mindustry/net/EditLog.java +++ b/core/src/io/anuke/mindustry/net/EditLog.java @@ -2,20 +2,20 @@ package io.anuke.mindustry.net; import io.anuke.mindustry.world.Block; -public class EditLog { - public String playername; - public Block block; - public int rotation; - public EditAction action; - - EditLog(String playername, Block block, int rotation, EditAction action) { - this.playername = playername; - this.block = block; - this.rotation = rotation; - this.action = action; - } - - public enum EditAction { - PLACE, BREAK +public class EditLog{ + public String playername; + public Block block; + public int rotation; + public EditAction action; + + EditLog(String playername, Block block, int rotation, EditAction action){ + this.playername = playername; + this.block = block; + this.rotation = rotation; + this.action = action; + } + + public enum EditAction{ + PLACE, BREAK } } diff --git a/core/src/io/anuke/mindustry/net/Host.java b/core/src/io/anuke/mindustry/net/Host.java index 631f74a726..36b5a5ecb9 100644 --- a/core/src/io/anuke/mindustry/net/Host.java +++ b/core/src/io/anuke/mindustry/net/Host.java @@ -1,6 +1,6 @@ package io.anuke.mindustry.net; -public class Host { +public class Host{ public final String name; public final String address; public final String mapname; diff --git a/core/src/io/anuke/mindustry/net/In.java b/core/src/io/anuke/mindustry/net/In.java index 712eec04bb..d00e0aba41 100644 --- a/core/src/io/anuke/mindustry/net/In.java +++ b/core/src/io/anuke/mindustry/net/In.java @@ -1,7 +1,9 @@ package io.anuke.mindustry.net; -/**Stores class nameas for remote method invocation for consistency's sake.*/ -public class In { +/** + * Stores class nameas for remote method invocation for consistency's sake. + */ +public class In{ public static final String normal = "Call"; public static final String entities = "CallEntity"; public static final String blocks = "CallBlocks"; diff --git a/core/src/io/anuke/mindustry/net/Interpolator.java b/core/src/io/anuke/mindustry/net/Interpolator.java index 1c0d4735d6..9748544b28 100644 --- a/core/src/io/anuke/mindustry/net/Interpolator.java +++ b/core/src/io/anuke/mindustry/net/Interpolator.java @@ -5,7 +5,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.ucore.util.Mathf; -public class Interpolator { +public class Interpolator{ //used for movement public Vector2 target = new Vector2(); public Vector2 last = new Vector2(); @@ -38,11 +38,12 @@ public class Interpolator { public void update(){ + /* if(pos.dst(target) > 128){ pos.set(target); lastUpdated = 0; updateSpacing = 16; - } + }*/ if(lastUpdated != 0 && updateSpacing != 0){ float timeSinceUpdate = TimeUtils.timeSinceMillis(lastUpdated); @@ -54,7 +55,7 @@ public class Interpolator { values = new float[targets.length]; } - for (int i = 0; i < values.length; i++) { + for(int i = 0; i < values.length; i++){ values[i] = Mathf.slerp(values[i], targets[i], alpha); } }else{ diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 41d5abc494..bd15fc6614 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -25,289 +25,393 @@ import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.ui; public class Net{ - public static final Object packetPoolLock = new Object(); + public static final Object packetPoolLock = new Object(); - private static boolean server; - private static boolean active; - private static boolean clientLoaded; - private static Array packetQueue = new Array<>(); - private static ObjectMap, Consumer> clientListeners = new ObjectMap<>(); - private static ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); - private static ClientProvider clientProvider; - private static ServerProvider serverProvider; + private static boolean server; + private static boolean active; + private static boolean clientLoaded; + private static Array packetQueue = new Array<>(); + private static ObjectMap, Consumer> clientListeners = new ObjectMap<>(); + private static ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); + private static ClientProvider clientProvider; + private static ServerProvider serverProvider; - private static IntMap streams = new IntMap<>(); + private static IntMap streams = new IntMap<>(); - /**Display a network error.*/ - public static void showError(String text){ - if(!headless){ - ui.showError(text); - }else{ - Log.err(text); - } - } + /** + * Display a network error. + */ + public static void showError(String text){ + if(!headless){ + ui.showError(text); + }else{ + Log.err(text); + } + } - /**Sets the client loaded status, or whether it will recieve normal packets from the server.*/ - public static void setClientLoaded(boolean loaded){ - clientLoaded = loaded; + /** + * Sets the client loaded status, or whether it will recieve normal packets from the server. + */ + public static void setClientLoaded(boolean loaded){ + clientLoaded = loaded; - if(loaded){ - //handle all packets that were skipped while loading - for(int i = 0; i < packetQueue.size; i ++){ + if(loaded){ + //handle all packets that were skipped while loading + for(int i = 0; i < packetQueue.size; i++){ Log.info("Processing {0} packet post-load.", ClassReflection.getSimpleName(packetQueue.get(i).getClass())); - handleClientReceived(packetQueue.get(i)); - } - } - //clear inbound packet queue - packetQueue.clear(); - } - - /**Connect to an address.*/ - public static void connect(String ip, int port) throws IOException{ - if(!active) { - clientProvider.connect(ip, port); - active = true; - server = false; - }else{ - throw new IOException("Already connected!"); - } - } + handleClientReceived(packetQueue.get(i)); + } + } + //clear inbound packet queue + packetQueue.clear(); + } - /**Host a server at an address*/ - public static void host(int port) throws IOException{ - serverProvider.host(port); - active = true; - server = true; + /** + * Connect to an address. + */ + public static void connect(String ip, int port) throws IOException{ + if(!active){ + clientProvider.connect(ip, port); + active = true; + server = false; + }else{ + throw new IOException("Already connected!"); + } + } - Timers.runTask(60f, Platform.instance::updateRPC); - } + /** + * Host a server at an address + */ + public static void host(int port) throws IOException{ + serverProvider.host(port); + active = true; + server = true; - /**Closes the server.*/ - public static void closeServer(){ + Timers.runTask(60f, Platform.instance::updateRPC); + } + + /** + * Closes the server. + */ + public static void closeServer(){ serverProvider.close(); server = false; active = false; } public static void disconnect(){ - clientProvider.disconnect(); - server = false; - active = false; - } + clientProvider.disconnect(); + server = false; + active = false; + } - /**Starts discovering servers on a different thread. Does not work with GWT. - * Callback is run on the main libGDX thread.*/ - public static void discoverServers(Consumer> cons){ - clientProvider.discover(cons); - } + /** + * Starts discovering servers on a different thread. Does not work with GWT. + * Callback is run on the main libGDX thread. + */ + public static void discoverServers(Consumer> cons){ + clientProvider.discover(cons); + } - /**Returns a list of all connections IDs.*/ - public static Array getConnections(){ - return (Array)serverProvider.getConnections(); - } + /** + * Returns a list of all connections IDs. + */ + public static Array getConnections(){ + return (Array) serverProvider.getConnections(); + } - /**Returns a connection by ID*/ - public static NetConnection getConnection(int id){ - return serverProvider.getByID(id); - } - - /**Send an object to all connected clients, or to the server if this is a client.*/ - public static void send(Object object, SendMode mode){ - if(server){ - if(serverProvider != null) serverProvider.send(object, mode); - }else { - if(clientProvider != null) clientProvider.send(object, mode); - } - } + /** + * Returns a connection by ID + */ + public static NetConnection getConnection(int id){ + return serverProvider.getByID(id); + } - /**Send an object to a certain client. Server-side only*/ - public static void sendTo(int id, Object object, SendMode mode){ - serverProvider.sendTo(id, object, mode); - } + /** + * Send an object to all connected clients, or to the server if this is a client. + */ + public static void send(Object object, SendMode mode){ + if(server){ + if(serverProvider != null) serverProvider.send(object, mode); + }else{ + if(clientProvider != null) clientProvider.send(object, mode); + } + } - /**Send an object to everyone EXCEPT certain client. Server-side only*/ - public static void sendExcept(int id, Object object, SendMode mode){ - serverProvider.sendExcept(id, object, mode); - } + /** + * Send an object to a certain client. Server-side only + */ + public static void sendTo(int id, Object object, SendMode mode){ + serverProvider.sendTo(id, object, mode); + } - /**Send a stream to a specific client. Server-side only.*/ - public static void sendStream(int id, Streamable stream){ - serverProvider.sendStream(id, stream); - } - - /**Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server.*/ - public static void setClientProvider(ClientProvider provider){ - Net.clientProvider = provider; - } + /** + * Send an object to everyone EXCEPT certain client. Server-side only + */ + public static void sendExcept(int id, Object object, SendMode mode){ + serverProvider.sendExcept(id, object, mode); + } - /**Sets the net serverProvider, e.g. what handles hosting a server.*/ - public static void setServerProvider(ServerProvider provider){ - Net.serverProvider = provider; - } + /** + * Send a stream to a specific client. Server-side only. + */ + public static void sendStream(int id, Streamable stream){ + serverProvider.sendStream(id, stream); + } - /**Registers a client listener for when an object is recieved.*/ - public static void handleClient(Class type, Consumer listener){ - clientListeners.put(type, listener); - } + /** + * Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server. + */ + public static void setClientProvider(ClientProvider provider){ + Net.clientProvider = provider; + } - /**Registers a server listener for when an object is recieved.*/ - public static void handleServer(Class type, BiConsumer listener){ - serverListeners.put(type, (BiConsumer) listener); - } - - /**Call to handle a packet being recieved for the client.*/ - public static void handleClientReceived(Object object){ + /** + * Sets the net serverProvider, e.g. what handles hosting a server. + */ + public static void setServerProvider(ServerProvider provider){ + Net.serverProvider = provider; + } - if(object instanceof StreamBegin) { - StreamBegin b = (StreamBegin) object; - streams.put(b.id, new StreamBuilder(b)); - }else if(object instanceof StreamChunk) { - StreamChunk c = (StreamChunk)object; - StreamBuilder builder = streams.get(c.id); - if(builder == null){ - throw new RuntimeException("Recieved stream chunk without a StreamBegin beforehand!"); - } - builder.add(c.data); - if(builder.isDone()){ - streams.remove(builder.id); - handleClientReceived(builder.build()); - } - }else if(clientListeners.get(object.getClass()) != null){ + /** + * Registers a client listener for when an object is recieved. + */ + public static void handleClient(Class type, Consumer listener){ + clientListeners.put(type, listener); + } - if(clientLoaded || ((object instanceof Packet) && ((Packet) object).isImportant())){ - if(clientListeners.get(object.getClass()) != null) clientListeners.get(object.getClass()).accept(object); - synchronized (packetPoolLock) { - Pooling.free(object); - } - }else if(!((object instanceof Packet) && ((Packet) object).isUnimportant())){ - packetQueue.add(object); - Log.info("Queuing packet {0}.", ClassReflection.getSimpleName(object.getClass())); - }else{ - synchronized (packetPoolLock) { - Pooling.free(object); - } - } - }else{ - Log.err("Unhandled packet type: '{0}'!", ClassReflection.getSimpleName(object.getClass())); - } - } + /** + * Registers a server listener for when an object is recieved. + */ + public static void handleServer(Class type, BiConsumer listener){ + serverListeners.put(type, (BiConsumer) listener); + } - /**Call to handle a packet being recieved for the server.*/ - public static void handleServerReceived(int connection, Object object){ + /** + * Call to handle a packet being recieved for the client. + */ + public static void handleClientReceived(Object object){ - if(serverListeners.get(object.getClass()) != null){ - if(serverListeners.get(object.getClass()) != null) serverListeners.get(object.getClass()).accept(connection, object); - synchronized (packetPoolLock) { - Pooling.free(object); - } - }else{ - Log.err("Unhandled packet type: '{0}'!", ClassReflection.getSimpleName(object.getClass())); - } - } + if(object instanceof StreamBegin){ + StreamBegin b = (StreamBegin) object; + streams.put(b.id, new StreamBuilder(b)); + }else if(object instanceof StreamChunk){ + StreamChunk c = (StreamChunk) object; + StreamBuilder builder = streams.get(c.id); + if(builder == null){ + throw new RuntimeException("Recieved stream chunk without a StreamBegin beforehand!"); + } + builder.add(c.data); + if(builder.isDone()){ + streams.remove(builder.id); + handleClientReceived(builder.build()); + } + }else if(clientListeners.get(object.getClass()) != null){ - /**Pings a host in an new thread. If an error occured, failed() should be called with the exception. */ - public static void pingHost(String address, int port, Consumer valid, Consumer failed){ - clientProvider.pingHost(address, port, valid, failed); - } + if(clientLoaded || ((object instanceof Packet) && ((Packet) object).isImportant())){ + if(clientListeners.get(object.getClass()) != null) + clientListeners.get(object.getClass()).accept(object); + synchronized(packetPoolLock){ + Pooling.free(object); + } + }else if(!((object instanceof Packet) && ((Packet) object).isUnimportant())){ + packetQueue.add(object); + Log.info("Queuing packet {0}.", ClassReflection.getSimpleName(object.getClass())); + }else{ + synchronized(packetPoolLock){ + Pooling.free(object); + } + } + }else{ + Log.err("Unhandled packet type: '{0}'!", ClassReflection.getSimpleName(object.getClass())); + } + } - /**Update client ping.*/ - public static void updatePing(){ - clientProvider.updatePing(); - } + /** + * Call to handle a packet being recieved for the server. + */ + public static void handleServerReceived(int connection, Object object){ - /**Get the client ping. Only valid after updatePing().*/ - public static int getPing(){ - return server() ? 0 : clientProvider.getPing(); - } - - /**Whether the net is active, e.g. whether this is a multiplayer game.*/ - public static boolean active(){ - return active; - } - - /**Whether this is a server or not.*/ - public static boolean server(){ - return server && active; - } + if(serverListeners.get(object.getClass()) != null){ + if(serverListeners.get(object.getClass()) != null) + serverListeners.get(object.getClass()).accept(connection, object); + synchronized(packetPoolLock){ + Pooling.free(object); + } + }else{ + Log.err("Unhandled packet type: '{0}'!", ClassReflection.getSimpleName(object.getClass())); + } + } - /**Whether this is a client or not.*/ - public static boolean client(){ - return !server && active; - } + /** + * Pings a host in an new thread. If an error occured, failed() should be called with the exception. + */ + public static void pingHost(String address, int port, Consumer valid, Consumer failed){ + clientProvider.pingHost(address, port, valid, failed); + } - public static void dispose(){ - if(clientProvider != null) clientProvider.dispose(); - if(serverProvider != null) serverProvider.dispose(); - clientProvider = null; - serverProvider = null; - server = false; - active = false; - } + /** + * Update client ping. + */ + public static void updatePing(){ + clientProvider.updatePing(); + } - public static void http(String url, String method, Consumer listener, Consumer failure){ - HttpRequest req = new HttpRequestBuilder().newRequest() - .method(method).url(url).build(); + /** + * Get the client ping. Only valid after updatePing(). + */ + public static int getPing(){ + return server() ? 0 : clientProvider.getPing(); + } - Gdx.net.sendHttpRequest(req, new HttpResponseListener() { - @Override - public void handleHttpResponse(HttpResponse httpResponse) { - listener.accept(httpResponse.getResultAsString()); - } + /** + * Whether the net is active, e.g. whether this is a multiplayer game. + */ + public static boolean active(){ + return active; + } - @Override - public void failed(Throwable t) { - failure.accept(t); - } + /** + * Whether this is a server or not. + */ + public static boolean server(){ + return server && active; + } - @Override - public void cancelled() {} - }); - } + /** + * Whether this is a client or not. + */ + public static boolean client(){ + return !server && active; + } - /**Client implementation.*/ - public interface ClientProvider { - /**Connect to a server.*/ - void connect(String ip, int port) throws IOException; - /**Send an object to the server.*/ - void send(Object object, SendMode mode); - /**Update the ping. Should be done every second or so.*/ - void updatePing(); - /**Get ping in milliseconds. Will only be valid after a call to updatePing.*/ - int getPing(); - /**Disconnect from the server.*/ - void disconnect(); - /**Discover servers. This should run the callback regardless of whether any servers are found. Should not block. - * Callback should be run on libGDX main thread.*/ + public static void dispose(){ + if(clientProvider != null) clientProvider.dispose(); + if(serverProvider != null) serverProvider.dispose(); + clientProvider = null; + serverProvider = null; + server = false; + active = false; + } + + public static void http(String url, String method, Consumer listener, Consumer failure){ + HttpRequest req = new HttpRequestBuilder().newRequest() + .method(method).url(url).build(); + + Gdx.net.sendHttpRequest(req, new HttpResponseListener(){ + @Override + public void handleHttpResponse(HttpResponse httpResponse){ + listener.accept(httpResponse.getResultAsString()); + } + + @Override + public void failed(Throwable t){ + failure.accept(t); + } + + @Override + public void cancelled(){ + } + }); + } + + public enum SendMode{ + tcp, udp + } + + /** + * Client implementation. + */ + public interface ClientProvider{ + /** + * Connect to a server. + */ + void connect(String ip, int port) throws IOException; + + /** + * Send an object to the server. + */ + void send(Object object, SendMode mode); + + /** + * Update the ping. Should be done every second or so. + */ + void updatePing(); + + /** + * Get ping in milliseconds. Will only be valid after a call to updatePing. + */ + int getPing(); + + /** + * Disconnect from the server. + */ + void disconnect(); + + /** + * Discover servers. This should run the callback regardless of whether any servers are found. Should not block. + * Callback should be run on libGDX main thread. + */ void discover(Consumer> callback); - /**Ping a host. If an error occured, failed() should be called with the exception. */ + + /** + * Ping a host. If an error occured, failed() should be called with the exception. + */ void pingHost(String address, int port, Consumer valid, Consumer failed); - /**Close all connections.*/ - void dispose(); - } - /**Server implementation.*/ - public interface ServerProvider { - /**Host a server at specified port.*/ - void host(int port) throws IOException; - /**Sends a large stream of data to a specific client.*/ - void sendStream(int id, Streamable stream); - /**Send an object to everyone connected.*/ - void send(Object object, SendMode mode); - /**Send an object to a specific client ID.*/ - void sendTo(int id, Object object, SendMode mode); - /**Send an object to everyone except a client ID.*/ - void sendExcept(int id, Object object, SendMode mode); - /**Close the server connection.*/ - void close(); - /**Return all connected users.*/ - Array getConnections(); - /**Returns a connection by ID.*/ - NetConnection getByID(int id); - /**Close all connections.*/ - void dispose(); - } + /** + * Close all connections. + */ + void dispose(); + } - public enum SendMode{ - tcp, udp - } + /** + * Server implementation. + */ + public interface ServerProvider{ + /** + * Host a server at specified port. + */ + void host(int port) throws IOException; + + /** + * Sends a large stream of data to a specific client. + */ + void sendStream(int id, Streamable stream); + + /** + * Send an object to everyone connected. + */ + void send(Object object, SendMode mode); + + /** + * Send an object to a specific client ID. + */ + void sendTo(int id, Object object, SendMode mode); + + /** + * Send an object to everyone except a client ID. + */ + void sendExcept(int id, Object object, SendMode mode); + + /** + * Close the server connection. + */ + void close(); + + /** + * Return all connected users. + */ + Array getConnections(); + + /** + * Returns a connection by ID. + */ + NetConnection getByID(int id); + + /** + * Close all connections. + */ + void dispose(); + } } diff --git a/core/src/io/anuke/mindustry/net/NetConnection.java b/core/src/io/anuke/mindustry/net/NetConnection.java index b4b25a76be..9c66726434 100644 --- a/core/src/io/anuke/mindustry/net/NetConnection.java +++ b/core/src/io/anuke/mindustry/net/NetConnection.java @@ -2,14 +2,18 @@ package io.anuke.mindustry.net; import io.anuke.mindustry.net.Net.SendMode; -public abstract class NetConnection { +public abstract class NetConnection{ public final int id; public final String address; - /**The current base snapshot that the client is absolutely confirmed to have recieved. - * All sent snapshots should be taking the diff from this base snapshot, if it isn't null.*/ + /** + * The current base snapshot that the client is absolutely confirmed to have recieved. + * All sent snapshots should be taking the diff from this base snapshot, if it isn't null. + */ public byte[] currentBaseSnapshot; - /**ID of the current base snapshot.*/ + /** + * ID of the current base snapshot. + */ public int currentBaseID = -1; public int lastSentBase = -1; @@ -17,9 +21,13 @@ public abstract class NetConnection { public byte[] lastSentRawSnapshot; public int lastSentSnapshotID = -1; - /**ID of last recieved client snapshot.*/ + /** + * ID of last recieved client snapshot. + */ public int lastRecievedClientSnapshot = -1; - /**Timestamp of last recieved snapshot.*/ + /** + * Timestamp of last recieved snapshot. + */ public long lastRecievedClientTime; public boolean hasConnected = false; @@ -34,5 +42,6 @@ public abstract class NetConnection { } public abstract void send(Object object, SendMode mode); + public abstract void close(); } diff --git a/core/src/io/anuke/mindustry/net/NetEvents.java b/core/src/io/anuke/mindustry/net/NetEvents.java index 749513a3a4..01dbfe5b90 100644 --- a/core/src/io/anuke/mindustry/net/NetEvents.java +++ b/core/src/io/anuke/mindustry/net/NetEvents.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.entities.Player; import static io.anuke.mindustry.Vars.maxTextLength; import static io.anuke.mindustry.Vars.playerGroup; -public class NetEvents { +public class NetEvents{ @Remote(called = Loc.server, targets = Loc.both, forward = true) public static void sendMessage(Player player, String message){ diff --git a/core/src/io/anuke/mindustry/net/NetworkIO.java b/core/src/io/anuke/mindustry/net/NetworkIO.java index 035decf9e3..8ece7638a3 100644 --- a/core/src/io/anuke/mindustry/net/NetworkIO.java +++ b/core/src/io/anuke/mindustry/net/NetworkIO.java @@ -24,7 +24,7 @@ import java.nio.ByteBuffer; import static io.anuke.mindustry.Vars.*; -public class NetworkIO { +public class NetworkIO{ public static void writeWorld(Player player, OutputStream os){ @@ -59,7 +59,7 @@ public class NetworkIO { stream.writeShort(world.width()); stream.writeShort(world.height()); - for (int i = 0; i < world.width() * world.height(); i++) { + for(int i = 0; i < world.width() * world.height(); i++){ Tile tile = world.tile(i); stream.writeByte(tile.getFloorID()); @@ -70,24 +70,25 @@ public class NetworkIO { stream.writeByte(tile.link); }else if(tile.entity != null){ stream.writeByte(Bits.packByte(tile.getTeamID(), tile.getRotation())); //team + rotation - stream.writeShort((short)tile.entity.health); //health + stream.writeShort((short) tile.entity.health); //health if(tile.entity.items != null) tile.entity.items.write(stream); if(tile.entity.power != null) tile.entity.power.write(stream); if(tile.entity.liquids != null) tile.entity.liquids.write(stream); + if(tile.entity.cons != null) tile.entity.cons.write(stream); tile.entity.write(stream); }else if(tile.getWallID() == 0){ int consecutives = 0; - for (int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++) { + for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ Tile nextTile = world.tile(j); if(nextTile.getFloorID() != tile.getFloorID() || nextTile.getWallID() != 0 || nextTile.elevation != tile.elevation){ break; } - consecutives ++; + consecutives++; } stream.writeByte(consecutives); @@ -106,12 +107,14 @@ public class NetworkIO { } } - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } } - /**Return whether a custom map is expected, and thus whether the client should wait for additional data.*/ + /** + * Return whether a custom map is expected, and thus whether the client should wait for additional data. + */ public static void loadWorld(InputStream is){ Player player = players[0]; @@ -131,7 +134,7 @@ public class NetworkIO { ObjectMap tags = new ObjectMap<>(); byte tagSize = stream.readByte(); - for (int i = 0; i < tagSize; i++) { + for(int i = 0; i < tagSize; i++){ String key = stream.readUTF(); String value = stream.readUTF(); tags.put(key, value); @@ -168,8 +171,8 @@ public class NetworkIO { Tile[][] tiles = world.createTiles(width, height); - for (int i = 0; i < width * height; i++) { - int x = i % width, y = i /width; + for(int i = 0; i < width * height; i++){ + int x = i % width, y = i / width; byte floorid = stream.readByte(); byte wallid = stream.readByte(); byte elevation = stream.readByte(); @@ -177,9 +180,9 @@ public class NetworkIO { Tile tile = new Tile(x, y, floorid, wallid); tile.elevation = elevation; - if (wallid == Blocks.blockpart.id) { + if(wallid == Blocks.blockpart.id){ tile.link = stream.readByte(); - }else if (tile.entity != null) { + }else if(tile.entity != null){ byte tr = stream.readByte(); short health = stream.readShort(); @@ -190,15 +193,16 @@ public class NetworkIO { tile.entity.health = health; tile.setRotation(rotation); - if (tile.entity.items != null) tile.entity.items.read(stream); - if (tile.entity.power != null) tile.entity.power.read(stream); - if (tile.entity.liquids != null) tile.entity.liquids.read(stream); + if(tile.entity.items != null) tile.entity.items.read(stream); + if(tile.entity.power != null) tile.entity.power.read(stream); + if(tile.entity.liquids != null) tile.entity.liquids.read(stream); + if(tile.entity.cons != null) tile.entity.cons.read(stream); tile.entity.read(stream); }else if(wallid == 0){ int consecutives = stream.readUnsignedByte(); - for (int j = i + 1; j < i + 1 + consecutives; j++) { + for(int j = i + 1; j < i + 1 + consecutives; j++){ int newx = j % width, newy = j / width; Tile newTile = new Tile(newx, newy, floorid, wallid); newTile.elevation = elevation; @@ -215,13 +219,13 @@ public class NetworkIO { state.teams = new TeamInfo(); byte teams = stream.readByte(); - for (int i = 0; i < teams; i++) { + for(int i = 0; i < teams; i++){ Team team = Team.all[stream.readByte()]; boolean ally = stream.readBoolean(); short cores = stream.readShort(); state.teams.add(team, ally); - for (int j = 0; j < cores; j++) { + for(int j = 0; j < cores; j++){ state.teams.get(team).cores.add(world.tile(stream.readInt())); } @@ -232,7 +236,7 @@ public class NetworkIO { world.endMapLoad(); - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } } @@ -248,10 +252,10 @@ public class NetworkIO { ByteBuffer buffer = ByteBuffer.allocate(128); - buffer.put((byte)host.getBytes().length); + buffer.put((byte) host.getBytes().length); buffer.put(host.getBytes()); - buffer.put((byte)map.getBytes().length); + buffer.put((byte) map.getBytes().length); buffer.put(map.getBytes()); buffer.putInt(playerGroup.size()); diff --git a/core/src/io/anuke/mindustry/net/Packet.java b/core/src/io/anuke/mindustry/net/Packet.java index 91f9b3a7de..ef34666dbb 100644 --- a/core/src/io/anuke/mindustry/net/Packet.java +++ b/core/src/io/anuke/mindustry/net/Packet.java @@ -5,10 +5,14 @@ import com.badlogic.gdx.utils.Pool.Poolable; import java.nio.ByteBuffer; public interface Packet extends Poolable{ - default void read(ByteBuffer buffer){} - default void write(ByteBuffer buffer){} + default void read(ByteBuffer buffer){ + } - default void reset() {} + default void write(ByteBuffer buffer){ + } + + default void reset(){ + } default boolean isImportant(){ return false; diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 7ba866677f..bcadd4c5cc 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -16,15 +16,34 @@ import java.nio.ByteBuffer; import static io.anuke.mindustry.Vars.world; -/**Class for storing all packets.*/ -public class Packets { +/** + * Class for storing all packets. + */ +public class Packets{ + + public enum KickReason{ + kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true), recentKick, nameInUse, idInUse, fastShoot, nameEmpty, customClient; + public final boolean quiet; + + KickReason(){ + quiet = false; + } + + KickReason(boolean quiet){ + this.quiet = quiet; + } + } + + public enum AdminAction{ + kick, ban, trace, wave + } public static class Connect implements Packet{ public int id; public String addressTCP; @Override - public boolean isImportant() { + public boolean isImportant(){ return true; } } @@ -33,7 +52,7 @@ public class Packets { public int id; @Override - public boolean isImportant() { + public boolean isImportant(){ return true; } } @@ -49,17 +68,17 @@ public class Packets { public int color; @Override - public void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer){ buffer.putInt(Version.build); IOUtils.writeString(buffer, name); IOUtils.writeString(buffer, usid); - buffer.put(mobile ? (byte)1 : 0); + buffer.put(mobile ? (byte) 1 : 0); buffer.putInt(color); buffer.put(Base64Coder.decode(uuid)); } @Override - public void read(ByteBuffer buffer) { + public void read(ByteBuffer buffer){ version = buffer.getInt(); name = IOUtils.readString(buffer); usid = IOUtils.readString(buffer); @@ -78,7 +97,7 @@ public class Packets { public int writeLength; @Override - public void read(ByteBuffer buffer) { + public void read(ByteBuffer buffer){ type = buffer.get(); priority = buffer.get(); writeLength = buffer.getShort(); @@ -88,29 +107,29 @@ public class Packets { } @Override - public void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer){ buffer.put(type); buffer.put(priority); - buffer.putShort((short)writeLength); + buffer.putShort((short) writeLength); writeBuffer.position(0); - for(int i = 0; i < writeLength; i ++){ + for(int i = 0; i < writeLength; i++){ buffer.put(writeBuffer.get()); } } @Override - public void reset() { + public void reset(){ priority = 0; } @Override - public boolean isImportant() { + public boolean isImportant(){ return priority == 1; } @Override - public boolean isUnimportant() { + public boolean isUnimportant(){ return priority == 2; } } @@ -127,7 +146,7 @@ public class Packets { public BuildRequest currentRequest; @Override - public void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer){ Player player = Vars.players[0]; buffer.putInt(lastSnapshot); @@ -138,33 +157,33 @@ public class Packets { buffer.putFloat(player.y); buffer.putFloat(player.pointerX); buffer.putFloat(player.pointerY); - buffer.put(player.isBoosting ? (byte)1 : 0); - buffer.put(player.isShooting ? (byte)1 : 0); + buffer.put(player.isBoosting ? (byte) 1 : 0); + buffer.put(player.isShooting ? (byte) 1 : 0); - buffer.put((byte)(Mathf.clamp(player.getVelocity().x, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision)); - buffer.put((byte)(Mathf.clamp(player.getVelocity().y, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision)); + buffer.put((byte) (Mathf.clamp(player.getVelocity().x, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision)); + buffer.put((byte) (Mathf.clamp(player.getVelocity().y, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision)); //saving 4 bytes, yay? - buffer.putShort((short)(player.rotation*2)); - buffer.putShort((short)(player.baseRotation*2)); + buffer.putShort((short) (player.rotation * 2)); + buffer.putShort((short) (player.baseRotation * 2)); buffer.putInt(player.getMineTile() == null ? -1 : player.getMineTile().packedPosition()); BuildRequest request = player.getCurrentRequest(); if(request != null){ - buffer.put(request.remove ? (byte)1 : 0); + buffer.put(request.remove ? (byte) 1 : 0); buffer.putInt(world.toPacked(request.x, request.y)); if(!request.remove){ - buffer.put((byte)request.recipe.id); - buffer.put((byte)request.rotation); + buffer.put((byte) request.recipe.id); + buffer.put((byte) request.rotation); } }else{ - buffer.put((byte)-1); + buffer.put((byte) -1); } } @Override - public void read(ByteBuffer buffer) { + public void read(ByteBuffer buffer){ lastSnapshot = buffer.getInt(); snapid = buffer.getInt(); timeSent = buffer.getLong(); @@ -177,17 +196,17 @@ public class Packets { shooting = buffer.get() == 1; xv = buffer.get() / Unit.velocityPercision; yv = buffer.get() / Unit.velocityPercision; - rotation = buffer.getShort()/2f; - baseRotation = buffer.getShort()/2f; + rotation = buffer.getShort() / 2f; + baseRotation = buffer.getShort() / 2f; mining = world.tile(buffer.getInt()); byte type = buffer.get(); - if (type != -1) { + if(type != -1){ int position = buffer.getInt(); - if (type == 1) { //remove + if(type == 1){ //remove currentRequest = new BuildRequest(position % world.width(), position / world.width()); - } else { //place + }else{ //place byte recipe = buffer.get(); byte rotation = buffer.get(); currentRequest = new BuildRequest(position % world.width(), position / world.width(), rotation, Recipe.getByID(recipe)); @@ -198,41 +217,28 @@ public class Packets { } } - public enum KickReason{ - kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true), recentKick, nameInUse, idInUse, fastShoot, nameEmpty, customClient; - public final boolean quiet; - - KickReason(){ quiet = false; } - - KickReason(boolean quiet){ - this.quiet = quiet; - } - } - - public enum AdminAction{ - kick, ban, trace, wave - } - - /**Marks the beginning of a stream.*/ + /** + * Marks the beginning of a stream. + */ public static class StreamBegin implements Packet{ private static int lastid; - public int id = lastid ++; + public int id = lastid++; public int total; public Class type; @Override - public void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer){ buffer.putInt(id); buffer.putInt(total); buffer.put(Registrator.getID(type)); } @Override - public void read(ByteBuffer buffer) { + public void read(ByteBuffer buffer){ id = buffer.getInt(); total = buffer.getInt(); - type = (Class)Registrator.getByID(buffer.get()); + type = (Class) Registrator.getByID(buffer.get()); } } @@ -241,14 +247,14 @@ public class Packets { public byte[] data; @Override - public void write(ByteBuffer buffer) { + public void write(ByteBuffer buffer){ buffer.putInt(id); - buffer.putShort((short)data.length); + buffer.putShort((short) data.length); buffer.put(data); } @Override - public void read(ByteBuffer buffer) { + public void read(ByteBuffer buffer){ id = buffer.getInt(); data = new byte[buffer.getShort()]; buffer.get(data); diff --git a/core/src/io/anuke/mindustry/net/Registrator.java b/core/src/io/anuke/mindustry/net/Registrator.java index f35a991d50..6dbabdcc15 100644 --- a/core/src/io/anuke/mindustry/net/Registrator.java +++ b/core/src/io/anuke/mindustry/net/Registrator.java @@ -3,25 +3,24 @@ package io.anuke.mindustry.net; import com.badlogic.gdx.utils.ObjectIntMap; import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.net.Packets.StreamBegin; -import io.anuke.mindustry.net.Packets.StreamChunk; -public class Registrator { +public class Registrator{ private static Class[] classes = { - StreamBegin.class, - StreamChunk.class, - WorldStream.class, - ConnectPacket.class, - ClientSnapshotPacket.class, - InvokePacket.class + StreamBegin.class, + StreamChunk.class, + WorldStream.class, + ConnectPacket.class, + ClientSnapshotPacket.class, + InvokePacket.class }; private static ObjectIntMap> ids = new ObjectIntMap<>(); static{ if(classes.length > 127) throw new RuntimeException("Can't have more than 127 registered classes!"); - for(int i = 0; i < classes.length; i ++){ + for(int i = 0; i < classes.length; i++){ if(!ClassReflection.isAssignableFrom(Packet.class, classes[i]) && - !ClassReflection.isAssignableFrom(Streamable.class, classes[i])) throw new RuntimeException("Not a packet: " + classes[i]); + !ClassReflection.isAssignableFrom(Streamable.class, classes[i])) + throw new RuntimeException("Not a packet: " + classes[i]); ids.put(classes[i], i); } } @@ -31,7 +30,7 @@ public class Registrator { } public static byte getID(Class type){ - return (byte)ids.get(type, -1); + return (byte) ids.get(type, -1); } public static Class[] getClasses(){ diff --git a/core/src/io/anuke/mindustry/net/Streamable.java b/core/src/io/anuke/mindustry/net/Streamable.java index 5815fdd845..a27ea42ced 100644 --- a/core/src/io/anuke/mindustry/net/Streamable.java +++ b/core/src/io/anuke/mindustry/net/Streamable.java @@ -11,6 +11,11 @@ import java.io.IOException; public class Streamable implements Packet{ public transient ByteArrayInputStream stream; + @Override + public boolean isImportant(){ + return true; + } + public static class StreamBuilder{ public final int id; public final Class type; @@ -25,15 +30,15 @@ public class Streamable implements Packet{ } public void add(byte[] bytes){ - try { + try{ stream.write(bytes); - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } } public Streamable build(){ - try { + try{ Streamable s = ClassReflection.newInstance(type); s.stream = new ByteArrayInputStream(stream.toByteArray()); return s; @@ -46,9 +51,4 @@ public class Streamable implements Packet{ return stream.size() >= total; } } - - @Override - public boolean isImportant() { - return true; - } } diff --git a/core/src/io/anuke/mindustry/net/TraceInfo.java b/core/src/io/anuke/mindustry/net/TraceInfo.java index 996363e1a7..512c8e85ff 100644 --- a/core/src/io/anuke/mindustry/net/TraceInfo.java +++ b/core/src/io/anuke/mindustry/net/TraceInfo.java @@ -1,10 +1,10 @@ package io.anuke.mindustry.net; import com.badlogic.gdx.utils.IntIntMap; -import io.anuke.mindustry.world.Block; import io.anuke.mindustry.content.blocks.Blocks; +import io.anuke.mindustry.world.Block; -public class TraceInfo { +public class TraceInfo{ public int playerid; public String ip; public boolean modclient; diff --git a/core/src/io/anuke/mindustry/net/ValidateException.java b/core/src/io/anuke/mindustry/net/ValidateException.java index 35fe5d6114..89923702de 100644 --- a/core/src/io/anuke/mindustry/net/ValidateException.java +++ b/core/src/io/anuke/mindustry/net/ValidateException.java @@ -2,11 +2,13 @@ package io.anuke.mindustry.net; import io.anuke.mindustry.entities.Player; -/**Thrown when a client sends invalid information.*/ +/** + * Thrown when a client sends invalid information. + */ public class ValidateException extends RuntimeException{ public final Player player; - public ValidateException(Player player, String s) { + public ValidateException(Player player, String s){ super(s); this.player = player; } diff --git a/core/src/io/anuke/mindustry/type/AmmoEntry.java b/core/src/io/anuke/mindustry/type/AmmoEntry.java index fc14db1cce..a4e0559df1 100644 --- a/core/src/io/anuke/mindustry/type/AmmoEntry.java +++ b/core/src/io/anuke/mindustry/type/AmmoEntry.java @@ -1,11 +1,13 @@ package io.anuke.mindustry.type; -/**Used to store ammo amounts in units and turrets.*/ +/** + * Used to store ammo amounts in units and turrets. + */ public class AmmoEntry{ public AmmoType type; public int amount; - public AmmoEntry(AmmoType type, int amount) { + public AmmoEntry(AmmoType type, int amount){ this.type = type; this.amount = amount; } diff --git a/core/src/io/anuke/mindustry/type/AmmoType.java b/core/src/io/anuke/mindustry/type/AmmoType.java index 88ad721a9e..90a5eb0601 100644 --- a/core/src/io/anuke/mindustry/type/AmmoType.java +++ b/core/src/io/anuke/mindustry/type/AmmoType.java @@ -11,32 +11,52 @@ public class AmmoType implements Content{ private static Array allTypes = new Array<>(32); public final byte id; - /**The item used. Always null if liquid isn't.*/ + /** + * The item used. Always null if liquid isn't. + */ public final Item item; - /**The liquid used. Always null if item isn't.*/ + /** + * The liquid used. Always null if item isn't. + */ public final Liquid liquid; - /**The resulting bullet. Never null.*/ + /** + * The resulting bullet. Never null. + */ public final BulletType bullet; - /**For item ammo, this is amount given per ammo item. - * For liquid ammo, this is amount used per shot.*/ + /** + * For item ammo, this is amount given per ammo item. + * For liquid ammo, this is amount used per shot. + */ public final float quantityMultiplier; - /**Reload speed multiplier.*/ + /** + * Reload speed multiplier. + */ public float reloadMultiplier = 1f; - /**Bullet recoil strength.*/ + /** + * Bullet recoil strength. + */ public float recoil = 0f; - /**Additional inaccuracy in degrees.*/ + /** + * Additional inaccuracy in degrees. + */ public float inaccuracy; - /**Effect created when shooting.*/ + /** + * Effect created when shooting. + */ public Effect shootEffect = Fx.none; - /**Extra smoke effect created when shooting.*/ + /** + * Extra smoke effect created when shooting. + */ public Effect smokeEffect = Fx.none; { - this.id = (byte)(lastID++); + this.id = (byte) (lastID++); allTypes.add(this); } - /**Creates an AmmoType with no liquid or item. Used for power-based ammo.*/ + /** + * Creates an AmmoType with no liquid or item. Used for power-based ammo. + */ public AmmoType(BulletType result){ this.item = null; this.liquid = null; @@ -45,7 +65,9 @@ public class AmmoType implements Content{ this.reloadMultiplier = 1f; } - /**Creates an AmmoType with an item.*/ + /** + * Creates an AmmoType with an item. + */ public AmmoType(Item item, BulletType result, float multiplier){ this.item = item; this.liquid = null; @@ -53,7 +75,9 @@ public class AmmoType implements Content{ this.quantityMultiplier = multiplier; } - /**Creates an AmmoType with a liquid.*/ + /** + * Creates an AmmoType with a liquid. + */ public AmmoType(Liquid liquid, BulletType result, float multiplier){ this.item = null; this.liquid = liquid; @@ -61,26 +85,28 @@ public class AmmoType implements Content{ this.quantityMultiplier = multiplier; } - /**Returns maximum distance the bullet this ammo type has can travel.*/ - public float getRange(){ - return bullet.speed * bullet.lifetime; - } - - @Override - public String getContentTypeName() { - return "ammotype"; - } - - @Override - public Array getAll() { - return allTypes; - } - - public static Array all() { + public static Array all(){ return allTypes; } public static AmmoType getByID(int id){ return allTypes.get(id); } + + /** + * Returns maximum distance the bullet this ammo type has can travel. + */ + public float getRange(){ + return bullet.speed * bullet.lifetime; + } + + @Override + public String getContentTypeName(){ + return "ammotype"; + } + + @Override + public Array getAll(){ + return allTypes; + } } diff --git a/core/src/io/anuke/mindustry/type/Category.java b/core/src/io/anuke/mindustry/type/Category.java index 58ccdb9015..6d75054b2f 100644 --- a/core/src/io/anuke/mindustry/type/Category.java +++ b/core/src/io/anuke/mindustry/type/Category.java @@ -1,5 +1,5 @@ package io.anuke.mindustry.type; -public enum Category { - weapon, production, distribution, liquid, power, defense, crafting, units +public enum Category{ + weapon, production, distribution, liquid, power, defense, crafting, units } diff --git a/core/src/io/anuke/mindustry/type/ContentList.java b/core/src/io/anuke/mindustry/type/ContentList.java index dc288f21ef..edeb482dca 100644 --- a/core/src/io/anuke/mindustry/type/ContentList.java +++ b/core/src/io/anuke/mindustry/type/ContentList.java @@ -3,11 +3,17 @@ package io.anuke.mindustry.type; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.game.Content; -/**Interface for a list of content to be loaded in {@link io.anuke.mindustry.core.ContentLoader}.*/ -public interface ContentList { - /**This method should create all the content.*/ +/** + * Interface for a list of content to be loaded in {@link io.anuke.mindustry.core.ContentLoader}. + */ +public interface ContentList{ + /** + * This method should create all the content. + */ void load(); - /**This method should return the list of the content of this type, for further loading.*/ + /** + * This method should return the list of the content of this type, for further loading. + */ Array getAll(); } diff --git a/core/src/io/anuke/mindustry/type/Item.java b/core/src/io/anuke/mindustry/type/Item.java index 31c66b51ba..18653372c6 100644 --- a/core/src/io/anuke/mindustry/type/Item.java +++ b/core/src/io/anuke/mindustry/type/Item.java @@ -15,95 +15,111 @@ import io.anuke.ucore.util.Strings; import io.anuke.ucore.util.ThreadArray; public class Item implements Comparable, UnlockableContent{ - private static final ThreadArray items = new ThreadArray<>(); + private static final ThreadArray items = new ThreadArray<>(); - public final int id; - public final String name; - public final String description; - public final Color color; - public TextureRegion region; + public final int id; + public final String name; + public final String description; + public final Color color; + public TextureRegion region; - /**type of the item; used for tabs and core acceptance. default value is {@link ItemType#resource}.*/ - public ItemType type = ItemType.resource; - /**how explosive this item is.*/ - public float explosiveness = 0f; - /**flammability above 0.3 makes this eleigible for item burners.*/ - public float flammability = 0f; - /**how radioactive this item is. 0=none, 1=chernobyl ground zero*/ - public float radioactivity; - /**how effective this item is as flux for smelting. 0 = not a flux, 0.5 = normal flux, 1 = very good*/ - public float fluxiness = 0f; - /**drill hardness of the item*/ - public int hardness = 0; - /**the burning color of this item*/ - public Color flameColor = Palette.darkFlame.cpy(); - /**base material cost of this item, used for calculating place times - * 1 cost = 1 tick added to build time*/ - public float cost = 3f; + /** + * type of the item; used for tabs and core acceptance. default value is {@link ItemType#resource}. + */ + public ItemType type = ItemType.resource; + /** + * how explosive this item is. + */ + public float explosiveness = 0f; + /** + * flammability above 0.3 makes this eleigible for item burners. + */ + public float flammability = 0f; + /** + * how radioactive this item is. 0=none, 1=chernobyl ground zero + */ + public float radioactivity; + /** + * how effective this item is as flux for smelting. 0 = not a flux, 0.5 = normal flux, 1 = very good + */ + public float fluxiness = 0f; + /** + * drill hardness of the item + */ + public int hardness = 0; + /** + * the burning color of this item + */ + public Color flameColor = Palette.darkFlame.cpy(); + /** + * base material cost of this item, used for calculating place times + * 1 cost = 1 tick added to build time + */ + public float cost = 3f; - public Item(String name, Color color) { - this.id = items.size; - this.name = name; - this.color = color; - this.description = Bundles.getOrNull("item." + this.name + ".description"); + public Item(String name, Color color){ + this.id = items.size; + this.name = name; + this.color = color; + this.description = Bundles.getOrNull("item." + this.name + ".description"); - items.add(this); + items.add(this); - if(!Bundles.has("item." + this.name + ".name")){ + if(!Bundles.has("item." + this.name + ".name")){ Log.err("Warning: item '" + name + "' is missing a localized name. Add the follow to bundle.properties:"); Log.err("item." + this.name + ".name=" + Strings.capitalize(name.replace('-', '_'))); } - } + } - public void load(){ - this.region = Draw.region("item-" + name); - } + public static Array all(){ + return Item.items; + } - @Override - public void displayInfo(Table table) { - ContentDisplay.displayItem(table, this); - } + public static Item getByID(int id){ + return items.get(id); + } - @Override - public String localizedName(){ - return Bundles.get("item." + this.name + ".name"); - } + public void load(){ + this.region = Draw.region("item-" + name); + } - @Override - public TextureRegion getContentIcon() { - return region; - } + @Override + public void displayInfo(Table table){ + ContentDisplay.displayItem(table, this); + } - @Override - public String toString() { - return localizedName(); - } + @Override + public String localizedName(){ + return Bundles.get("item." + this.name + ".name"); + } - @Override - public int compareTo(Item item) { - return Integer.compare(id, item.id); - } + @Override + public TextureRegion getContentIcon(){ + return region; + } - @Override - public String getContentName() { - return name; - } + @Override + public String toString(){ + return localizedName(); + } - @Override - public String getContentTypeName() { - return "item"; - } + @Override + public int compareTo(Item item){ + return Integer.compare(id, item.id); + } - @Override - public Array getAll() { - return all(); - } + @Override + public String getContentName(){ + return name; + } - public static Array all() { - return Item.items; - } + @Override + public String getContentTypeName(){ + return "item"; + } - public static Item getByID(int id){ - return items.get(id); - } + @Override + public Array getAll(){ + return all(); + } } diff --git a/core/src/io/anuke/mindustry/type/ItemStack.java b/core/src/io/anuke/mindustry/type/ItemStack.java index 6ab73ca5af..5714050602 100644 --- a/core/src/io/anuke/mindustry/type/ItemStack.java +++ b/core/src/io/anuke/mindustry/type/ItemStack.java @@ -1,15 +1,15 @@ package io.anuke.mindustry.type; public class ItemStack{ - public io.anuke.mindustry.type.Item item; - public int amount; - - public ItemStack(io.anuke.mindustry.type.Item item, int amount){ - this.item = item; - this.amount = amount; - } + public io.anuke.mindustry.type.Item item; + public int amount; - public boolean equals(ItemStack other){ - return other != null && other.item == item && other.amount == amount; - } + public ItemStack(io.anuke.mindustry.type.Item item, int amount){ + this.item = item; + this.amount = amount; + } + + public boolean equals(ItemStack other){ + return other != null && other.item == item && other.amount == amount; + } } diff --git a/core/src/io/anuke/mindustry/type/ItemType.java b/core/src/io/anuke/mindustry/type/ItemType.java index 5a80183522..fb676443bb 100644 --- a/core/src/io/anuke/mindustry/type/ItemType.java +++ b/core/src/io/anuke/mindustry/type/ItemType.java @@ -1,10 +1,16 @@ package io.anuke.mindustry.type; -public enum ItemType { - /**Not used for anything besides crafting inside blocks.*/ +public enum ItemType{ + /** + * Not used for anything besides crafting inside blocks. + */ resource, - /**Can be used for constructing blocks. Only materials are accepted into the core.*/ + /** + * Can be used for constructing blocks. Only materials are accepted into the core. + */ material, - /**Only used as ammo for turrets.*/ + /** + * Only used as ammo for turrets. + */ ammo } diff --git a/core/src/io/anuke/mindustry/type/Liquid.java b/core/src/io/anuke/mindustry/type/Liquid.java index 85c65198aa..20410304c1 100644 --- a/core/src/io/anuke/mindustry/type/Liquid.java +++ b/core/src/io/anuke/mindustry/type/Liquid.java @@ -10,89 +10,108 @@ import io.anuke.mindustry.ui.ContentDisplay; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Bundles; +import io.anuke.ucore.util.ThreadArray; public class Liquid implements UnlockableContent{ - private static final Array liquids = new Array<>(); + private static final Array liquids = new ThreadArray<>(); - public final Color color; - public final String name; - public final String description; - public final int id; + public final Color color; + public final String name; + public final String description; + public final int id; - /**0-1, 0 is completely inflammable, anything above that may catch fire when exposed to heat, 0.5+ is very flammable.*/ - public float flammability; - /**temperature: 0.5 is 'room' temperature, 0 is very cold, 1 is molten hot*/ - public float temperature = 0.5f; - /**how much heat this liquid can store. 0.75=water (high), anything lower is probably less dense and bad at cooling.*/ - public float heatCapacity = 0.5f; - /**how thick this liquid is. 0.5=water (relatively viscous), 1 would be something like tar (very slow)*/ - public float viscosity = 0.5f; - /**how prone to exploding this liquid is, when heated. 0 = nothing, 1 = nuke*/ - public float explosiveness; - /**the burning color of this liquid*/ - public Color flameColor = Color.valueOf("ffb763"); - /**The associated status effect.*/ - public StatusEffect effect = StatusEffects.none; - /**Pump tier. Controls which pumps can use this liquid.*/ - public int tier; - /**Displayed icon.*/ - public TextureRegion iconRegion; - - public Liquid(String name, Color color) { - this.name = name; - this.color = new Color(color); + /** + * 0-1, 0 is completely inflammable, anything above that may catch fire when exposed to heat, 0.5+ is very flammable. + */ + public float flammability; + /** + * temperature: 0.5 is 'room' temperature, 0 is very cold, 1 is molten hot + */ + public float temperature = 0.5f; + /** + * how much heat this liquid can store. 0.75=water (high), anything lower is probably less dense and bad at cooling. + */ + public float heatCapacity = 0.5f; + /** + * how thick this liquid is. 0.5=water (relatively viscous), 1 would be something like tar (very slow) + */ + public float viscosity = 0.5f; + /** + * how prone to exploding this liquid is, when heated. 0 = nothing, 1 = nuke + */ + public float explosiveness; + /** + * the burning color of this liquid + */ + public Color flameColor = Color.valueOf("ffb763"); + /** + * The associated status effect. + */ + public StatusEffect effect = StatusEffects.none; + /** + * Pump tier. Controls which pumps can use this liquid. + */ + public int tier; + /** + * Displayed icon. + */ + public TextureRegion iconRegion; - this.id = liquids.size; - this.description = Bundles.getOrNull("liquid." + name + ".description"); + public Liquid(String name, Color color){ + this.name = name; + this.color = new Color(color); - Liquid.liquids.add(this); - } + this.id = liquids.size; + this.description = Bundles.getOrNull("liquid." + name + ".description"); - @Override - public void load() { - iconRegion = Draw.region("liquid-icon-" + name); - } + Liquid.liquids.add(this); + } - @Override - public void displayInfo(Table table) { - ContentDisplay.displayLiquid(table, this); - } + public static Array all(){ + return Liquid.liquids; + } - @Override - public String localizedName(){ - return Bundles.get("liquid."+ this.name + ".name"); - } + public static Liquid getByID(int id){ + return liquids.get(id); + } - @Override - public TextureRegion getContentIcon() { - return iconRegion; - } + @Override + public void load(){ + iconRegion = Draw.region("liquid-icon-" + name); + } - @Override - public String toString(){ - return localizedName(); - } + @Override + public void displayInfo(Table table){ + ContentDisplay.displayLiquid(table, this); + } - @Override - public String getContentName() { - return name; - } + @Override + public String localizedName(){ + return Bundles.get("liquid." + this.name + ".name"); + } - @Override - public String getContentTypeName() { - return "liquid"; - } + @Override + public TextureRegion getContentIcon(){ + return iconRegion; + } - @Override - public Array getAll() { - return all(); - } + @Override + public String toString(){ + return localizedName(); + } - public static Array all() { - return Liquid.liquids; - } + @Override + public String getContentName(){ + return name; + } - public static Liquid getByID(int id){ - return liquids.get(id); - } + @Override + public String getContentTypeName(){ + return "liquid"; + } + + @Override + public Array getAll(){ + return all(); + } } diff --git a/core/src/io/anuke/mindustry/type/Mech.java b/core/src/io/anuke/mindustry/type/Mech.java index c2397535ff..98640fe292 100644 --- a/core/src/io/anuke/mindustry/type/Mech.java +++ b/core/src/io/anuke/mindustry/type/Mech.java @@ -10,64 +10,64 @@ import io.anuke.ucore.scene.ui.layout.Table; //TODO merge unit type with mech public class Mech extends Upgrade implements UnlockableContent{ - public boolean flying; + public boolean flying; - public float speed = 1.1f; - public float maxSpeed = 1.1f; - public float boostSpeed = 0.75f; - public float drag = 0.4f; - public float mass = 1f; - public float armor = 1f; + public float speed = 1.1f; + public float maxSpeed = 1.1f; + public float boostSpeed = 0.75f; + public float drag = 0.4f; + public float mass = 1f; + public float armor = 1f; - public float mineSpeed = 1f; - public int drillPower = -1; - public float carryWeight = 10f; - public float buildPower = 1f; - public boolean canRepair = false; - public Color trailColor = Color.valueOf("ffd37f"); + public float mineSpeed = 1f; + public int drillPower = -1; + public float carryWeight = 10f; + public float buildPower = 1f; + public boolean canRepair = false; + public Color trailColor = Color.valueOf("ffd37f"); - public float weaponOffsetX, weaponOffsetY; + public float weaponOffsetX, weaponOffsetY; - public Weapon weapon = Weapons.blaster; + public Weapon weapon = Weapons.blaster; - public int itemCapacity = 30; - public int ammoCapacity = 100; + public int itemCapacity = 30; + public int ammoCapacity = 100; - public TextureRegion baseRegion, legRegion, region, iconRegion; + public TextureRegion baseRegion, legRegion, region, iconRegion; - public Mech(String name, boolean flying){ - super(name); - this.flying = flying; - } - - @Override - public void displayInfo(Table table) { - ContentDisplay.displayMech(table, this); - } - - @Override - public TextureRegion getContentIcon() { - return iconRegion; - } + public Mech(String name, boolean flying){ + super(name); + this.flying = flying; + } @Override - public String getContentName() { + public void displayInfo(Table table){ + ContentDisplay.displayMech(table, this); + } + + @Override + public TextureRegion getContentIcon(){ + return iconRegion; + } + + @Override + public String getContentName(){ return name; } @Override - public String getContentTypeName() { + public String getContentTypeName(){ return "mech"; } - @Override - public void load() { - if (!flying){ - legRegion = Draw.region(name + "-leg"); - baseRegion = Draw.region(name + "-base"); - } + @Override + public void load(){ + if(!flying){ + legRegion = Draw.region(name + "-leg"); + baseRegion = Draw.region(name + "-base"); + } - region = Draw.region(name); - iconRegion = Draw.region("mech-icon-"+ name); - } + region = Draw.region(name); + iconRegion = Draw.region("mech-icon-" + name); + } } diff --git a/core/src/io/anuke/mindustry/type/Recipe.java b/core/src/io/anuke/mindustry/type/Recipe.java index 50b490e67b..36b5e4bca6 100644 --- a/core/src/io/anuke/mindustry/type/Recipe.java +++ b/core/src/io/anuke/mindustry/type/Recipe.java @@ -19,9 +19,7 @@ import io.anuke.ucore.util.Strings; import java.util.Arrays; -import static io.anuke.mindustry.Vars.control; -import static io.anuke.mindustry.Vars.debug; -import static io.anuke.mindustry.Vars.headless; +import static io.anuke.mindustry.Vars.*; public class Recipe implements UnlockableContent{ private static int lastid; @@ -40,7 +38,7 @@ public class Recipe implements UnlockableContent{ private Recipe[] recipeDependencies; public Recipe(Category category, Block result, ItemStack... requirements){ - this.id = lastid ++; + this.id = lastid++; this.result = result; this.requirements = requirements; this.category = category; @@ -58,91 +56,10 @@ public class Recipe implements UnlockableContent{ recipeMap.put(result, this); } - public Recipe setDependencies(Block... blocks){ - this.dependencies = blocks; - return this; - } - - public Recipe setDesktop(){ - desktopOnly = true; - return this; - } - - public Recipe setDebug(){ - debugOnly = true; - return this; - } - - @Override - public void displayInfo(Table table) { - ContentDisplay.displayRecipe(table, this); - } - - @Override - public String localizedName() { - return result.formalName; - } - - @Override - public TextureRegion getContentIcon() { - return result.getEditorIcon(); - } - - @Override - public void init() { - if(!Bundles.has("block." + result.name + ".name")) { - Log.err("WARNING: Recipe block '{0}' does not have a formal name defined. Add the following to bundle.properties:", result.name); - Log.err("block.{0}.name={1}", result.name, Strings.capitalize(result.name.replace('-', '_'))); - }/*else if(result.fullDescription == null){ - Log.err("WARNING: Recipe block '{0}' does not have a description defined.", result.name); - }*/ - } - - @Override - public String getContentName() { - return result.name; - } - - @Override - public String getContentTypeName() { - return "recipe"; - } - - @Override - public void onUnlock() { - for(OrderedMap map : result.stats.toMap().values()){ - for(StatValue value : map.values()){ - if(value instanceof ContentStatValue){ - ContentStatValue stat = (ContentStatValue)value; - UnlockableContent[] content = stat.getValueContent(); - for(UnlockableContent c : content){ - control.database().unlockContent(c); - } - } - } - } - } - - @Override - public UnlockableContent[] getDependencies() { - if(dependencies == null){ - return null; - }else if(recipeDependencies == null){ - recipeDependencies = new Recipe[dependencies.length]; - for (int i = 0; i < recipeDependencies.length; i++) { - recipeDependencies[i] = Recipe.getByResult(dependencies[i]); - } - } - return recipeDependencies; - } - - @Override - public Array getAll() { - return allRecipes; - } - - /**Returns unlocked recipes in a category. - * Do not call on the server backend, as unlocking does not exist!*/ + /** + * Returns unlocked recipes in a category. + * Do not call on the server backend, as unlocking does not exist! + */ public static void getUnlockedByCategory(Category category, Array r){ if(headless){ throw new RuntimeException("Not enabled on the headless backend!"); @@ -150,17 +67,19 @@ public class Recipe implements UnlockableContent{ r.clear(); for(Recipe recipe : allRecipes){ - if(recipe.category == category && (Vars.control.database().isUnlocked(recipe) || (debug && recipe.debugOnly))) { + if(recipe.category == category && (Vars.control.database().isUnlocked(recipe) || (debug && recipe.debugOnly))){ r.add(recipe); } } } - /**Returns all recipes in a category.*/ + /** + * Returns all recipes in a category. + */ public static void getByCategory(Category category, Array r){ r.clear(); for(Recipe recipe : allRecipes){ - if(recipe.category == category) { + if(recipe.category == category){ r.add(recipe); } } @@ -181,4 +100,92 @@ public class Recipe implements UnlockableContent{ return allRecipes.get(id); } } + + public Recipe setDesktop(){ + desktopOnly = true; + return this; + } + + public Recipe setDebug(){ + debugOnly = true; + return this; + } + + @Override + public boolean isHidden(){ + return debugOnly; + } + + @Override + public void displayInfo(Table table){ + ContentDisplay.displayRecipe(table, this); + } + + @Override + public String localizedName(){ + return result.formalName; + } + + @Override + public TextureRegion getContentIcon(){ + return result.getEditorIcon(); + } + + @Override + public void init(){ + if(!Bundles.has("block." + result.name + ".name")){ + Log.err("WARNING: Recipe block '{0}' does not have a formal name defined. Add the following to bundle.properties:", result.name); + Log.err("block.{0}.name={1}", result.name, Strings.capitalize(result.name.replace('-', '_'))); + }/*else if(result.fullDescription == null){ + Log.err("WARNING: Recipe block '{0}' does not have a description defined.", result.name); + }*/ + } + + @Override + public String getContentName(){ + return result.name; + } + + @Override + public String getContentTypeName(){ + return "recipe"; + } + + @Override + public void onUnlock(){ + for(OrderedMap map : result.stats.toMap().values()){ + for(StatValue value : map.values()){ + if(value instanceof ContentStatValue){ + ContentStatValue stat = (ContentStatValue) value; + UnlockableContent[] content = stat.getValueContent(); + for(UnlockableContent c : content){ + control.database().unlockContent(c); + } + } + } + } + } + + @Override + public UnlockableContent[] getDependencies(){ + if(dependencies == null){ + return null; + }else if(recipeDependencies == null){ + recipeDependencies = new Recipe[dependencies.length]; + for(int i = 0; i < recipeDependencies.length; i++){ + recipeDependencies[i] = Recipe.getByResult(dependencies[i]); + } + } + return recipeDependencies; + } + + public Recipe setDependencies(Block... blocks){ + this.dependencies = blocks; + return this; + } + + @Override + public Array getAll(){ + return allRecipes; + } } diff --git a/core/src/io/anuke/mindustry/type/StatusEffect.java b/core/src/io/anuke/mindustry/type/StatusEffect.java index 17a04881de..fa9bcab529 100644 --- a/core/src/io/anuke/mindustry/type/StatusEffect.java +++ b/core/src/io/anuke/mindustry/type/StatusEffect.java @@ -7,75 +7,90 @@ import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.game.Content; public class StatusEffect implements Content{ - private static final Array array = new Array<>(); - private static int lastid; + private static final Array array = new Array<>(); + private static int lastid; - /**Duration of this status effect in ticks at maximum power.*/ - public final float baseDuration; - public final int id; + /** + * Duration of this status effect in ticks at maximum power. + */ + public final float baseDuration; + public final int id; - public float damageMultiplier = 1f; //damage dealt - public float armorMultiplier = 1f; //armor points - public float speedMultiplier = 1f; //speed + public float damageMultiplier = 1f; //damage dealt + public float armorMultiplier = 1f; //armor points + public float speedMultiplier = 1f; //speed - /**Set of 'opposite' effects, which will decrease the duration of this effect when applied.*/ - protected ObjectSet opposites = new ObjectSet<>(); - /**The strength of time decrease when met with an opposite effect, as a fraction of the other's duration.*/ - protected float oppositeScale = 0.5f; + /** + * Set of 'opposite' effects, which will decrease the duration of this effect when applied. + */ + protected ObjectSet opposites = new ObjectSet<>(); + /** + * The strength of time decrease when met with an opposite effect, as a fraction of the other's duration. + */ + protected float oppositeScale = 0.5f; - public StatusEffect(float baseDuration){ - this.baseDuration = baseDuration; + public StatusEffect(float baseDuration){ + this.baseDuration = baseDuration; - id = lastid++; - array.add(this); - } + id = lastid++; + array.add(this); + } - /**Runs every tick on the affected unit while time is greater than 0.*/ - public void update(Unit unit, float time){} + public static StatusEffect getByID(int id){ + return array.get(id); + } - /**Called when transitioning between two status effects. - * @param to The state to transition to - * @param time The current status effect time - * @param newTime The time that the new status effect will last*/ - public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ - if(opposites.contains(to)){ - time -= newTime*oppositeScale; - if(time > 0) { - return result.set(this, time); - } - } + public static Array all(){ + return array; + } - return result.set(to, newTime); - } + /** + * Runs every tick on the affected unit while time is greater than 0. + */ + public void update(Unit unit, float time){ + } - /**Called when this effect transitions to a new status effect.*/ - public void onTransition(Unit unit, StatusEffect to){} + /** + * Called when transitioning between two status effects. + * + * @param to The state to transition to + * @param time The current status effect time + * @param newTime The time that the new status effect will last + */ + public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ + if(opposites.contains(to)){ + time -= newTime * oppositeScale; + if(time > 0){ + return result.set(this, time); + } + } - public boolean isOpposite(StatusEffect other){ - return opposites.size > 0 && opposites.contains(other); - } + return result.set(to, newTime); + } - public void setOpposites(StatusEffect... effects){ - for(StatusEffect e : effects){ - opposites.add(e); - } - } + /** + * Called when this effect transitions to a new status effect. + */ + public void onTransition(Unit unit, StatusEffect to){ + } - @Override - public String getContentTypeName() { - return "statuseffect"; - } + public boolean isOpposite(StatusEffect other){ + return opposites.size > 0 && opposites.contains(other); + } - @Override - public Array getAll() { - return null; - } + public void setOpposites(StatusEffect... effects){ + for(StatusEffect e : effects){ + opposites.add(e); + } + } - public static StatusEffect getByID(int id){ - return array.get(id); - } + @Override + public String getContentTypeName(){ + return "statuseffect"; + } - public static Array all(){ - return array; - } + @Override + public Array getAll(){ + return null; + } } diff --git a/core/src/io/anuke/mindustry/type/Upgrade.java b/core/src/io/anuke/mindustry/type/Upgrade.java index 192e6ced1c..49157843ec 100644 --- a/core/src/io/anuke/mindustry/type/Upgrade.java +++ b/core/src/io/anuke/mindustry/type/Upgrade.java @@ -15,13 +15,29 @@ public abstract class Upgrade implements Content{ public final String description; public Upgrade(String name){ - this.id = lastid ++; + this.id = lastid++; this.name = name; - this.description = Bundles.get("upgrade."+name+".description"); + this.description = Bundles.get("upgrade." + name + ".description"); upgrades.add(this); } + public static void forEach(Consumer type, Predicate pred){ + for(Upgrade u : upgrades){ + if(pred.test(u)){ + type.accept((T) u); + } + } + } + + public static Array all(){ + return upgrades; + } + + public static T getByID(byte id){ + return (T) upgrades.get(id); + } + public String localizedName(){ return Bundles.get("upgrade." + name + ".name"); } @@ -32,23 +48,7 @@ public abstract class Upgrade implements Content{ } @Override - public Array getAll() { + public Array getAll(){ return all(); } - - public static void forEach(Consumer type, Predicate pred){ - for(Upgrade u : upgrades){ - if(pred.test(u)){ - type.accept((T)u); - } - } - } - - public static Array all() { - return upgrades; - } - - public static T getByID(byte id){ - return (T)upgrades.get(id); - } } diff --git a/core/src/io/anuke/mindustry/type/Weapon.java b/core/src/io/anuke/mindustry/type/Weapon.java index cfb8f8eeb1..a5d3610048 100644 --- a/core/src/io/anuke/mindustry/type/Weapon.java +++ b/core/src/io/anuke/mindustry/type/Weapon.java @@ -19,164 +19,191 @@ import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Translator; -public class Weapon extends Upgrade { - /**minimum cursor distance from player, fixes 'cross-eyed' shooting.*/ - protected static float minPlayerDist = 20f; - /**ammo type map. set with setAmmo()*/ - protected OrderedMap ammoMap = new OrderedMap<>(); - /**shell ejection effect*/ - protected Effect ejectEffect = Fx.none; - /**weapon reload in frames*/ - protected float reload; - /**amount of shots per fire*/ - protected int shots = 1; - /**spacing in degrees between multiple shots, if applicable*/ - protected float spacing = 12f; - /**inaccuracy of degrees of each shot*/ - protected float inaccuracy = 0f; - /**intensity and duration of each shot's screen shake*/ - protected float shake = 0f; - /**visual weapon knockback.*/ - protected float recoil = 1.5f; - /**shoot barrel y offset*/ - protected float length = 3f; - /**shoot barrel x offset.*/ - protected float width = 4f; - /**fraction of velocity that is random*/ - protected float velocityRnd = 0f; - /**whether to shoot the weapons in different arms one after another, rather than all at once*/ - protected boolean roundrobin = false; - /**translator for vector calulations*/ - protected Translator tr = new Translator(); +public class Weapon extends Upgrade{ + /** + * minimum cursor distance from player, fixes 'cross-eyed' shooting. + */ + protected static float minPlayerDist = 20f; + public TextureRegion equipRegion, region; + /** + * ammo type map. set with setAmmo() + */ + protected OrderedMap ammoMap = new OrderedMap<>(); + /** + * shell ejection effect + */ + protected Effect ejectEffect = Fx.none; + /** + * weapon reload in frames + */ + protected float reload; + /** + * amount of shots per fire + */ + protected int shots = 1; + /** + * spacing in degrees between multiple shots, if applicable + */ + protected float spacing = 12f; + /** + * inaccuracy of degrees of each shot + */ + protected float inaccuracy = 0f; + /** + * intensity and duration of each shot's screen shake + */ + protected float shake = 0f; + /** + * visual weapon knockback. + */ + protected float recoil = 1.5f; + /** + * shoot barrel y offset + */ + protected float length = 3f; + /** + * shoot barrel x offset. + */ + protected float width = 4f; + /** + * fraction of velocity that is random + */ + protected float velocityRnd = 0f; + /** + * whether to shoot the weapons in different arms one after another, rather than all at once + */ + protected boolean roundrobin = false; + /** + * translator for vector calulations + */ + protected Translator tr = new Translator(); - public TextureRegion equipRegion, region; + protected Weapon(String name){ + super(name); + } - protected Weapon(String name){ - super(name); - } + @Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true) + public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){ + if(player == null) return; + //clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals + //messing with the firerate or any other stats does not affect the server (take that, script kiddies!) + if(Net.client() && player == Vars.players[0]){ + return; + } - @Override - public void load() { - equipRegion = Draw.region(name + "-equip"); - region = Draw.region(name); - } + shootDirect(player, x, y, rotation, left); + } - @Override - public String getContentTypeName() { - return "weapon"; - } + @Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true) + public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){ + if(shooter == null) return; + shootDirect(shooter, x, y, rotation, left); + } - public void update(ShooterTrait shooter, float pointerX, float pointerY){ + public static void shootDirect(ShooterTrait shooter, float x, float y, float rotation, boolean left){ + Weapon weapon = shooter.getWeapon(); + + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy))); + + AmmoType type = shooter.getInventory().getAmmo(); + + if(type == null) return; + + weapon.tr.trns(rotation + 180f, type.recoil); + + shooter.getVelocity().add(weapon.tr); + + weapon.tr.trns(rotation, 3f); + + Effects.shake(weapon.shake, weapon.shake, x, y); + Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left)); + Effects.effect(type.shootEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter); + Effects.effect(type.smokeEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter); + + //reset timer for remote players + shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload); + } + + @Override + public void load(){ + equipRegion = Draw.region(name + "-equip"); + region = Draw.region(name); + } + + @Override + public String getContentTypeName(){ + return "weapon"; + } + + public void update(ShooterTrait shooter, float pointerX, float pointerY){ update(shooter, true, pointerX, pointerY); update(shooter, false, pointerX, pointerY); } - private void update(ShooterTrait shooter, boolean left, float pointerX, float pointerY){ - if(shooter.getInventory().hasAmmo() && shooter.getTimer().get(shooter.getShootTimer(left), reload)){ - if(roundrobin){ - shooter.getTimer().reset(shooter.getShootTimer(!left), reload/2f); - } + private void update(ShooterTrait shooter, boolean left, float pointerX, float pointerY){ + if(shooter.getInventory().hasAmmo() && shooter.getTimer().get(shooter.getShootTimer(left), reload)){ + if(roundrobin){ + shooter.getTimer().reset(shooter.getShootTimer(!left), reload / 2f); + } - tr.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY()); - if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist); + tr.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY()); + if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist); - float cx = tr.x + shooter.getX(), cy = tr.y + shooter.getY(); + float cx = tr.x + shooter.getX(), cy = tr.y + shooter.getY(); - float ang = tr.angle(); - tr.trns(ang - 90, width * Mathf.sign(left), length); + float ang = tr.angle(); + tr.trns(ang - 90, width * Mathf.sign(left), length); - shoot(shooter, shooter.getX() + tr.x, shooter.getY() + tr.y, Angles.angle(shooter.getX() + tr.x, shooter.getY() + tr.y, cx, cy), left); - } - } + shoot(shooter, shooter.getX() + tr.x, shooter.getY() + tr.y, Angles.angle(shooter.getX() + tr.x, shooter.getY() + tr.y, cx, cy), left); + } + } - public float getRecoil(ShooterTrait player, boolean left){ - return (1f-Mathf.clamp(player.getTimer().getTime(player.getShootTimer(left))/reload))*recoil; - } + public float getRecoil(ShooterTrait player, boolean left){ + return (1f - Mathf.clamp(player.getTimer().getTime(player.getShootTimer(left)) / reload)) * recoil; + } - public float getRecoil() { - return recoil; - } + public float getRecoil(){ + return recoil; + } - public float getReload(){ - return reload; - } + public float getReload(){ + return reload; + } - public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){ - if(Net.client()){ - //call it directly, don't invoke on server - shootDirect(p, x, y, angle, left); - }else{ - if(p instanceof Player){ //players need special weapon handling logic - CallEntity.onPlayerShootWeapon((Player)p, x, y, angle, left); + public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){ + if(Net.client()){ + //call it directly, don't invoke on server + shootDirect(p, x, y, angle, left); + }else{ + if(p instanceof Player){ //players need special weapon handling logic + CallEntity.onPlayerShootWeapon((Player) p, x, y, angle, left); }else{ CallEntity.onGenericShootWeapon(p, x, y, angle, left); } - } + } - p.getInventory().useAmmo(); - } - - public Iterable getAcceptedItems(){ - return ammoMap.orderedKeys(); - } - - public AmmoType getAmmoType(Item item){ - return ammoMap.get(item); - } - - protected void setAmmo(AmmoType... types){ - for(AmmoType type : types){ - ammoMap.put(type.item, type); - } - } - - void bullet(ShooterTrait owner, float x, float y, float angle){ - if(owner == null || !owner.getInventory().hasAmmo()) return; - - tr.trns(angle, 3f); - Bullet.create(owner.getInventory().getAmmo().bullet, - owner, owner.getTeam(), x + tr.x, y + tr.y, angle, (1f-velocityRnd) + Mathf.random(velocityRnd)); - } - - @Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true) - public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){ - if(player == null) return; - //clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals - //messing with the firerate or any other stats does not affect the server (take that, script kiddies!) - if(Net.client() && player == Vars.players[0]){ - return; - } - - shootDirect(player, x, y, rotation, left); - } - - @Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true) - public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){ - if(shooter == null) return; - shootDirect(shooter, x, y, rotation, left); + p.getInventory().useAmmo(); } - public static void shootDirect(ShooterTrait shooter, float x, float y, float rotation, boolean left){ - Weapon weapon = shooter.getWeapon(); + public Iterable getAcceptedItems(){ + return ammoMap.orderedKeys(); + } - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy))); + public AmmoType getAmmoType(Item item){ + return ammoMap.get(item); + } - AmmoType type = shooter.getInventory().getAmmo(); + protected void setAmmo(AmmoType... types){ + for(AmmoType type : types){ + ammoMap.put(type.item, type); + } + } - if(type == null) return; + void bullet(ShooterTrait owner, float x, float y, float angle){ + if(owner == null || !owner.getInventory().hasAmmo()) return; - weapon.tr.trns(rotation + 180f, type.recoil); - - shooter.getVelocity().add(weapon.tr); - - weapon.tr.trns(rotation, 3f); - - Effects.shake(weapon.shake, weapon.shake, x, y); - Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left)); - Effects.effect(type.shootEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter); - Effects.effect(type.smokeEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter); - - //reset timer for remote players - shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload); - } + tr.trns(angle, 3f); + Bullet.create(owner.getInventory().getAmmo().bullet, + owner, owner.getTeam(), x + tr.x, y + tr.y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd)); + } } diff --git a/core/src/io/anuke/mindustry/type/WeatherEvent.java b/core/src/io/anuke/mindustry/type/WeatherEvent.java index 24577af6b9..66871cc439 100644 --- a/core/src/io/anuke/mindustry/type/WeatherEvent.java +++ b/core/src/io/anuke/mindustry/type/WeatherEvent.java @@ -12,22 +12,12 @@ public class WeatherEvent implements Content{ public final String name; public WeatherEvent(String name){ - this.id = lastid ++; + this.id = lastid++; this.name = name; all.add(this); } - @Override - public String getContentTypeName() { - return "weatherevent"; - } - - @Override - public Array getAll() { - return all(); - } - public static Array all(){ return all; } @@ -35,4 +25,14 @@ public class WeatherEvent implements Content{ public static WeatherEvent getByID(int id){ return all.get(id); } + + @Override + public String getContentTypeName(){ + return "weatherevent"; + } + + @Override + public Array getAll(){ + return all(); + } } diff --git a/core/src/io/anuke/mindustry/ui/BorderImage.java b/core/src/io/anuke/mindustry/ui/BorderImage.java index ab6e1c6b86..bc9ed30002 100644 --- a/core/src/io/anuke/mindustry/ui/BorderImage.java +++ b/core/src/io/anuke/mindustry/ui/BorderImage.java @@ -10,34 +10,35 @@ import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.layout.Unit; public class BorderImage extends Image{ - private float thickness = 3f; - - public BorderImage(){} - - public BorderImage(Texture texture){ - super(texture); - } - - public BorderImage(Texture texture, float thick){ - super(texture); - thickness = thick; - } + private float thickness = 3f; - public BorderImage(TextureRegion region, float thick){ - super(region); - thickness = thick; - } - - @Override - public void draw(Batch batch, float alpha){ - super.draw(batch, alpha); - - float scaleX = getScaleX(); - float scaleY = getScaleY(); - - Draw.color(Palette.accent); - Lines.stroke(Unit.dp.scl(thickness)); - Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); - Draw.reset(); - } + public BorderImage(){ + } + + public BorderImage(Texture texture){ + super(texture); + } + + public BorderImage(Texture texture, float thick){ + super(texture); + thickness = thick; + } + + public BorderImage(TextureRegion region, float thick){ + super(region); + thickness = thick; + } + + @Override + public void draw(Batch batch, float alpha){ + super.draw(batch, alpha); + + float scaleX = getScaleX(); + float scaleY = getScaleY(); + + Draw.color(Palette.accent); + Lines.stroke(Unit.dp.scl(thickness)); + Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); + Draw.reset(); + } } diff --git a/core/src/io/anuke/mindustry/ui/ContentDisplay.java b/core/src/io/anuke/mindustry/ui/ContentDisplay.java index 916654b314..181e5704f1 100644 --- a/core/src/io/anuke/mindustry/ui/ContentDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ContentDisplay.java @@ -18,16 +18,16 @@ import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Bundles; -public class ContentDisplay { +public class ContentDisplay{ public static void displayRecipe(Table table, Recipe recipe){ Block block = recipe.result; table.table(title -> { - int size = 8*6; + int size = 8 * 6; if(block instanceof Turret){ - size = (8 * block.size + 2) * (7 - block.size*2); + size = (8 * block.size + 2) * (7 - block.size * 2); } title.addImage(Draw.region("block-icon-" + block.name)).size(size); @@ -58,7 +58,7 @@ public class ContentDisplay { table.add("$text.category." + cat.name()).color(Palette.accent).fillX(); table.row(); - for (BlockStat stat : map.keys()){ + for(BlockStat stat : map.keys()){ table.table(inset -> { inset.left(); inset.add("[LIGHT_GRAY]" + stat.localized() + ":[] "); @@ -92,13 +92,13 @@ public class ContentDisplay { table.left().defaults().fillX(); - table.add(Bundles.format("text.item.explosiveness", (int)(item.explosiveness * 100))); + table.add(Bundles.format("text.item.explosiveness", (int) (item.explosiveness * 100))); table.row(); - table.add(Bundles.format("text.item.flammability", (int)(item.flammability * 100))); + table.add(Bundles.format("text.item.flammability", (int) (item.flammability * 100))); table.row(); - table.add(Bundles.format("text.item.radioactivity", (int)(item.radioactivity * 100))); + table.add(Bundles.format("text.item.radioactivity", (int) (item.radioactivity * 100))); table.row(); - table.add(Bundles.format("text.item.fluxiness", (int)(item.fluxiness * 100))); + table.add(Bundles.format("text.item.fluxiness", (int) (item.fluxiness * 100))); table.row(); table.add(Bundles.format("text.item.hardness", item.hardness)); table.row(); @@ -127,15 +127,15 @@ public class ContentDisplay { table.left().defaults().fillX(); - table.add(Bundles.format("text.item.explosiveness", (int)(liquid.explosiveness * 100))); + table.add(Bundles.format("text.item.explosiveness", (int) (liquid.explosiveness * 100))); table.row(); - table.add(Bundles.format("text.item.flammability", (int)(liquid.flammability * 100))); + table.add(Bundles.format("text.item.flammability", (int) (liquid.flammability * 100))); table.row(); - table.add(Bundles.format("text.liquid.heatcapacity", (int)(liquid.heatCapacity * 100))); + table.add(Bundles.format("text.liquid.heatcapacity", (int) (liquid.heatCapacity * 100))); table.row(); - table.add(Bundles.format("text.liquid.temperature", (int)(liquid.temperature * 100))); + table.add(Bundles.format("text.liquid.temperature", (int) (liquid.temperature * 100))); table.row(); - table.add(Bundles.format("text.liquid.viscosity", (int)(liquid.viscosity * 100))); + table.add(Bundles.format("text.liquid.viscosity", (int) (liquid.viscosity * 100))); table.row(); } diff --git a/core/src/io/anuke/mindustry/ui/GridImage.java b/core/src/io/anuke/mindustry/ui/GridImage.java index 13d2c175b0..01792f5fbb 100644 --- a/core/src/io/anuke/mindustry/ui/GridImage.java +++ b/core/src/io/anuke/mindustry/ui/GridImage.java @@ -2,41 +2,40 @@ package io.anuke.mindustry.ui; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureRegion; - import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.Element; public class GridImage extends Element{ - private int imageWidth, imageHeight; - - public GridImage(int w, int h){ - this.imageWidth = w; - this.imageHeight = h; - } + private int imageWidth, imageHeight; - public void draw(Batch batch, float alpha){ - TextureRegion blank = Draw.region("white"); - - float xspace = (getWidth() / imageWidth); - float yspace = (getHeight() / imageHeight); - float s = 1f; + public GridImage(int w, int h){ + this.imageWidth = w; + this.imageHeight = h; + } - int minspace = 10; + public void draw(Batch batch, float alpha){ + TextureRegion blank = Draw.region("white"); - int jumpx = (int)(Math.max(minspace, xspace) / xspace); - int jumpy = (int)(Math.max(minspace, yspace)/ yspace); - - for(int x = 0; x <= imageWidth; x += jumpx){ - batch.draw(blank, (int)(getX() + xspace * x - s), getY() - s, 2, getHeight()+ (x == imageWidth ? 1: 0)); - } - - for(int y = 0; y <= imageHeight; y += jumpy){ - batch.draw(blank, getX() - s, (int)(getY() + y * yspace - s), getWidth(), 2); - } - } - - public void setImageSize(int w, int h){ - this.imageWidth = w; - this.imageHeight = h; - } + float xspace = (getWidth() / imageWidth); + float yspace = (getHeight() / imageHeight); + float s = 1f; + + int minspace = 10; + + int jumpx = (int) (Math.max(minspace, xspace) / xspace); + int jumpy = (int) (Math.max(minspace, yspace) / yspace); + + for(int x = 0; x <= imageWidth; x += jumpx){ + batch.draw(blank, (int) (getX() + xspace * x - s), getY() - s, 2, getHeight() + (x == imageWidth ? 1 : 0)); + } + + for(int y = 0; y <= imageHeight; y += jumpy){ + batch.draw(blank, getX() - s, (int) (getY() + y * yspace - s), getWidth(), 2); + } + } + + public void setImageSize(int w, int h){ + this.imageWidth = w; + this.imageHeight = h; + } } diff --git a/core/src/io/anuke/mindustry/ui/IntFormat.java b/core/src/io/anuke/mindustry/ui/IntFormat.java index ad753bd871..6c4431a4b0 100644 --- a/core/src/io/anuke/mindustry/ui/IntFormat.java +++ b/core/src/io/anuke/mindustry/ui/IntFormat.java @@ -2,13 +2,15 @@ package io.anuke.mindustry.ui; import io.anuke.ucore.util.Bundles; -/**A low-garbage way to format bundle strings.*/ -public class IntFormat { +/** + * A low-garbage way to format bundle strings. + */ +public class IntFormat{ private final StringBuilder builder = new StringBuilder(); private final String text; private int lastValue = Integer.MIN_VALUE; - public IntFormat(String text) { + public IntFormat(String text){ this.text = text; } diff --git a/core/src/io/anuke/mindustry/ui/ItemImage.java b/core/src/io/anuke/mindustry/ui/ItemImage.java index e5260938b4..5dab85a67d 100644 --- a/core/src/io/anuke/mindustry/ui/ItemImage.java +++ b/core/src/io/anuke/mindustry/ui/ItemImage.java @@ -9,31 +9,27 @@ import io.anuke.ucore.scene.ui.layout.Stack; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Unit; -public class ItemImage extends Stack { +public class ItemImage extends Stack{ - public ItemImage(TextureRegion region, Supplier text) { + public ItemImage(TextureRegion region, Supplier text){ Table t = new Table().left().bottom(); t.label(text).color(Color.DARK_GRAY).padBottom(-22).get().setFontScale(Unit.dp.scl(0.5f)); t.row(); t.label(text).get().setFontScale(Unit.dp.scl(0.5f)); - Image image = new Image(region); - - add(image); + add(new Image(region)); add(t); } - public ItemImage(ItemStack stack) { + public ItemImage(ItemStack stack){ Table t = new Table().left().bottom(); t.add(stack.amount + "").color(Color.DARK_GRAY).padBottom(-22).get().setFontScale(Unit.dp.scl(0.5f)); t.row(); t.add(stack.amount + "").get().setFontScale(Unit.dp.scl(0.5f)); - Image image = new Image(stack.item.region); - - add(image); + add(new Image(stack.item.region)); add(t); } } diff --git a/core/src/io/anuke/mindustry/ui/Links.java b/core/src/io/anuke/mindustry/ui/Links.java index 517083b91f..09ebd501d8 100644 --- a/core/src/io/anuke/mindustry/ui/Links.java +++ b/core/src/io/anuke/mindustry/ui/Links.java @@ -3,18 +3,18 @@ package io.anuke.mindustry.ui; import com.badlogic.gdx.graphics.Color; import io.anuke.ucore.util.Bundles; -public class Links { +public class Links{ private static LinkEntry[] links; private static void createLinks(){ links = new LinkEntry[]{ - new LinkEntry("discord", "https://discord.gg/BKADYds", Color.valueOf("7289da")), - new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")), - new LinkEntry("wiki", "http://mindustry.wikia.com/wiki/Mindustry_Wiki", Color.valueOf("0f142f")), - new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")), - new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")), - new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")), - new LinkEntry("dev-builds", "https://github.com/Anuken/Mindustry/wiki", Color.valueOf("fafbfc")) + new LinkEntry("discord", "https://discord.gg/BKADYds", Color.valueOf("7289da")), + new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")), + new LinkEntry("wiki", "http://mindustry.wikia.com/wiki/Mindustry_Wiki", Color.valueOf("0f142f")), + new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")), + new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")), + new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")), + new LinkEntry("dev-builds", "https://github.com/Anuken/Mindustry/wiki", Color.valueOf("fafbfc")) }; } @@ -30,10 +30,10 @@ public class Links { public final String name, description, link; public final Color color; - public LinkEntry(String name, String link, Color color) { + public LinkEntry(String name, String link, Color color){ this.name = name; this.color = color; - this.description = Bundles.getNotNull("text.link." + name +".description"); + this.description = Bundles.getNotNull("text.link." + name + ".description"); this.link = link; } } diff --git a/core/src/io/anuke/mindustry/ui/MenuButton.java b/core/src/io/anuke/mindustry/ui/MenuButton.java index 5bce02d2b1..ec3b273d39 100644 --- a/core/src/io/anuke/mindustry/ui/MenuButton.java +++ b/core/src/io/anuke/mindustry/ui/MenuButton.java @@ -7,32 +7,32 @@ import io.anuke.ucore.scene.ui.TextButton; public class MenuButton extends TextButton{ - public MenuButton(String icon, String text, Listenable clicked){ - this(icon, text, null, clicked); - } - - public MenuButton(String icon, String text, String description, Listenable clicked){ - super("default"); - float s = 66f; + public MenuButton(String icon, String text, Listenable clicked){ + this(icon, text, null, clicked); + } - clicked(clicked); + public MenuButton(String icon, String text, String description, Listenable clicked){ + super("default"); + float s = 66f; - clearChildren(); + clicked(clicked); - margin(0); + clearChildren(); - table(t -> { - t.addImage(icon).size(14*3); - t.update(() -> t.setBackground(getClickListener().isOver() || getClickListener().isVisualPressed() ? "button-over" : "button")); - }).size(s - 5, s); + margin(0); + + table(t -> { + t.addImage(icon).size(14 * 3); + t.update(() -> t.setBackground(getClickListener().isOver() || getClickListener().isVisualPressed() ? "button-over" : "button")); + }).size(s - 5, s); - table(t -> { - t.add(text).wrap().growX().get().setAlignment(Align.center, Align.left); - if(description != null){ - t.row(); - t.add(description).color(Color.LIGHT_GRAY); - } - }).padLeft(5).growX(); - } + table(t -> { + t.add(text).wrap().growX().get().setAlignment(Align.center, Align.left); + if(description != null){ + t.row(); + t.add(description).color(Color.LIGHT_GRAY); + } + }).padLeft(5).growX(); + } } diff --git a/core/src/io/anuke/mindustry/ui/Minimap.java b/core/src/io/anuke/mindustry/ui/Minimap.java index 9e469bac1f..1b0f563cf6 100644 --- a/core/src/io/anuke/mindustry/ui/Minimap.java +++ b/core/src/io/anuke/mindustry/ui/Minimap.java @@ -16,7 +16,7 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.renderer; import static io.anuke.mindustry.Vars.showFog; -public class Minimap extends Table { +public class Minimap extends Table{ public Minimap(){ super("button"); @@ -26,17 +26,17 @@ public class Minimap extends Table { Image image = new Image(new TextureRegionDrawable(new TextureRegion())){ @Override - public void draw(Batch batch, float parentAlpha) { + public void draw(Batch batch, float parentAlpha){ if(renderer.minimap().getRegion() == null) return; - TextureRegionDrawable draw = (TextureRegionDrawable)getDrawable(); + TextureRegionDrawable draw = (TextureRegionDrawable) getDrawable(); draw.getRegion().setRegion(renderer.minimap().getRegion()); super.draw(batch, parentAlpha); if(renderer.minimap().getTexture() != null){ renderer.minimap().drawEntities(x, y, width, height); } - if(showFog) { + if(showFog){ renderer.fog().getTexture().setFilter(TextureFilter.Nearest, TextureFilter.Nearest); draw.getRegion().setTexture(renderer.fog().getTexture()); @@ -53,7 +53,7 @@ public class Minimap extends Table { }; addListener(new InputListener(){ - public boolean scrolled (InputEvent event, float x, float y, int amount) { + public boolean scrolled(InputEvent event, float x, float y, int amount){ renderer.minimap().zoomBy(amount); return true; } diff --git a/core/src/io/anuke/mindustry/ui/MobileButton.java b/core/src/io/anuke/mindustry/ui/MobileButton.java index af996644d7..dfbf1b161c 100644 --- a/core/src/io/anuke/mindustry/ui/MobileButton.java +++ b/core/src/io/anuke/mindustry/ui/MobileButton.java @@ -1,15 +1,16 @@ package io.anuke.mindustry.ui; +import com.badlogic.gdx.utils.Align; import io.anuke.ucore.function.Listenable; import io.anuke.ucore.scene.ui.ImageButton; -public class MobileButton extends ImageButton { +public class MobileButton extends ImageButton{ - public MobileButton(String icon, float isize, String text, Listenable listener) { + public MobileButton(String icon, float isize, String text, Listenable listener){ super(icon); resizeImage(isize); clicked(listener); row(); - add(text); + add(text).growX().wrap().center().get().setAlignment(Align.center, Align.center); } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java index 027f595892..ed489a0630 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java @@ -16,7 +16,7 @@ import io.anuke.ucore.util.OS; import static io.anuke.mindustry.Vars.ios; import static io.anuke.mindustry.Vars.ui; -public class AboutDialog extends FloatingDialog { +public class AboutDialog extends FloatingDialog{ private static ObjectSet bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "trello"); public AboutDialog(){ @@ -51,21 +51,21 @@ public class AboutDialog extends FloatingDialog { table.table(i -> { i.background("button"); - i.addImage("icon-" + link.name).size(14*3f); - }).size(h-5, h); + i.addImage("icon-" + link.name).size(14 * 3f); + }).size(h - 5, h); table.table(inset -> { - inset.add("[accent]"+link.name.replace("-", " ")).growX().left(); + inset.add("[accent]" + link.name.replace("-", " ")).growX().left(); inset.row(); inset.labelWrap(link.description).width(w - 100f).color(Color.LIGHT_GRAY).growX(); }).padLeft(8); - table.addImageButton("icon-link", 14*3, () -> { + table.addImageButton("icon-link", 14 * 3, () -> { if(!Gdx.net.openURI(link.link)){ ui.showError("$text.linkfail"); Gdx.app.getClipboard().setContents(link.link); } - }).size(h-5, h); + }).size(h - 5, h); in.add(table).size(w, h).padTop(5).row(); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java index c95577232f..dbfd1273f6 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java @@ -7,7 +7,7 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.*; -public class AdminsDialog extends FloatingDialog { +public class AdminsDialog extends FloatingDialog{ public AdminsDialog(){ super("$text.server.admins"); @@ -40,7 +40,7 @@ public class AdminsDialog extends FloatingDialog { res.labelWrap("[LIGHT_GRAY]" + info.lastName).width(w - h - 24f); res.add().growX(); - res.addImageButton("icon-cancel", 14*3, () -> { + res.addImageButton("icon-cancel", 14 * 3, () -> { ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> { netServer.admins.unAdminPlayer(info.id); for(Player player : playerGroup.all()){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java index d8165c0ae6..012bbe6ee1 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java @@ -6,7 +6,7 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.*; -public class BansDialog extends FloatingDialog { +public class BansDialog extends FloatingDialog{ public BansDialog(){ super("$text.server.bans"); @@ -40,7 +40,7 @@ public class BansDialog extends FloatingDialog { res.labelWrap("IP: [LIGHT_GRAY]" + info.lastIP + "\n[]Name: [LIGHT_GRAY]" + info.lastName).width(w - h - 24f); res.add().growX(); - res.addImageButton("icon-cancel", 14*3, () -> { + res.addImageButton("icon-cancel", 14 * 3, () -> { ui.showConfirm("$text.confirm", "$text.confirmunban", () -> { netServer.admins.unbanPlayerID(info.id); setup(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ChangelogDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ChangelogDialog.java index b525117aa9..62c3aa646f 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ChangelogDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ChangelogDialog.java @@ -25,7 +25,7 @@ public class ChangelogDialog extends FloatingDialog{ content().add("$text.changelog.loading"); - if(!ios && !OS.isMac) { + if(!ios && !OS.isMac){ Changelogs.getChangelog(result -> { versions = result; Gdx.app.postRunnable(this::setup); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java index 8b8db3f845..5a06b32a73 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java @@ -22,7 +22,7 @@ public class ColorPickDialog extends Dialog{ Table table = new Table(); content().add(table); - for(int i = 0; i < playerColors.length; i ++){ + for(int i = 0; i < playerColors.length; i++){ Color color = playerColors[i]; ImageButton button = table.addImageButton("white", "toggle", 34, () -> { @@ -32,12 +32,12 @@ public class ColorPickDialog extends Dialog{ button.setChecked(players[0].color.equals(color)); button.getStyle().imageUpColor = color; - if(i%4 == 3){ + if(i % 4 == 3){ table.row(); } } - keyDown(key->{ + keyDown(key -> { if(key == Keys.ESCAPE || key == Keys.BACK) hide(); }); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ContentInfoDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ContentInfoDialog.java index da26c251f9..fe791c4030 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ContentInfoDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ContentInfoDialog.java @@ -4,10 +4,10 @@ import io.anuke.mindustry.game.UnlockableContent; import io.anuke.ucore.scene.ui.ScrollPane; import io.anuke.ucore.scene.ui.layout.Table; -public class ContentInfoDialog extends FloatingDialog { +public class ContentInfoDialog extends FloatingDialog{ public ContentInfoDialog(){ - super("$text.info"); + super("$text.info.title"); addCloseButton(); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java index 987866200a..c9c2901a6b 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java @@ -7,24 +7,24 @@ import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.KeybindDialog; public class ControlsDialog extends KeybindDialog{ - - public ControlsDialog(){ - setDialog(); - - setFillParent(true); - title().setAlignment(Align.center); - getTitleTable().row(); - getTitleTable().add(new Image("white")) - .growX().height(3f).pad(4f).get().setColor(Palette.accent); - } - - @Override - public void addCloseButton(){ - buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f); - - keyDown(key->{ - if(key == Keys.ESCAPE || key == Keys.BACK) - hide(); - }); - } + + public ControlsDialog(){ + setDialog(); + + setFillParent(true); + title().setAlignment(Align.center); + getTitleTable().row(); + getTitleTable().add(new Image("white")) + .growX().height(3f).pad(4f).get().setColor(Palette.accent); + } + + @Override + public void addCloseButton(){ + buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f); + + keyDown(key -> { + if(key == Keys.ESCAPE || key == Keys.BACK) + hide(); + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java index 19e889b863..e4571b2447 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java @@ -8,7 +8,7 @@ import io.anuke.ucore.scene.ui.Dialog; import static io.anuke.mindustry.Vars.discordURL; import static io.anuke.mindustry.Vars.ui; -public class DiscordDialog extends Dialog { +public class DiscordDialog extends Dialog{ public DiscordDialog(){ super("", "dialog"); @@ -39,10 +39,10 @@ public class DiscordDialog extends Dialog { buttons().defaults().size(170f, 50); buttons().addButton("$text.back", this::hide); - buttons().addButton("$text.copylink", () ->{ + buttons().addButton("$text.copylink", () -> { Gdx.app.getClipboard().setContents(discordURL); }); - buttons().addButton("$text.openlink", () ->{ + buttons().addButton("$text.openlink", () -> { if(!Gdx.net.openURI(discordURL)){ ui.showError("$text.linkfail"); Gdx.app.getClipboard().setContents(discordURL); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java index b13324ca66..c61ac8d4bd 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java @@ -23,320 +23,319 @@ import java.util.Arrays; import static io.anuke.mindustry.Vars.gwt; -public class FileChooser extends FloatingDialog { - private Table files; - private FileHandle homeDirectory = gwt ? Gdx.files.internal("") : Gdx.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : +public class FileChooser extends FloatingDialog{ + public static Predicate pngFilter = file -> file.extension().equalsIgnoreCase("png"); + public static Predicate mapFilter = file -> file.extension().equalsIgnoreCase(Vars.mapExtension); + public static Predicate jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg"); + public static Predicate defaultFilter = file -> true; + private Table files; + private FileHandle homeDirectory = gwt ? Gdx.files.internal("") : Gdx.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : Gdx.files.getExternalStoragePath()); - private FileHandle directory = homeDirectory; - private ScrollPane pane; - private TextField navigation, filefield; - private TextButton ok; - private FileHistory stack = new FileHistory(); - private Predicate filter; - private Consumer selectListener; - private boolean open; - - public FileChooser(String title, boolean open, Consumer result){ - this(title, defaultFilter, open, result); - } + private FileHandle directory = homeDirectory; + private ScrollPane pane; + private TextField navigation, filefield; + private TextButton ok; + private FileHistory stack = new FileHistory(); + private Predicate filter; + private Consumer selectListener; + private boolean open; - public FileChooser(String title, Predicate filter, boolean open, Consumer result){ - super(title); - this.open = open; - this.filter = filter; - this.selectListener = result; - } + public FileChooser(String title, boolean open, Consumer result){ + this(title, defaultFilter, open, result); + } - private void setupWidgets(){ - //getCell(content()).maxWidth(UIUtils.portrait() ? Gdx.graphics.getWidth() : Gdx.graphics.getWidth()/Unit.dp.scl(2f)); - content().margin(-10); - - Table content = new Table(); - - filefield = new TextField(); - filefield.setOnlyFontChars(false); - if(!open) Platform.instance.addDialog(filefield); - filefield.setDisabled(open); + public FileChooser(String title, Predicate filter, boolean open, Consumer result){ + super(title); + this.open = open; + this.filter = filter; + this.selectListener = result; + } - ok = new TextButton(open ? "$text.load" : "$text.save"); - - ok.clicked(() -> { - if(ok.isDisabled()) return; - if(selectListener != null) - selectListener.accept(directory.child(filefield.getText())); - hide(); - }); - - filefield.changed(() -> { - ok.setDisabled(filefield.getText().replace(" ", "").isEmpty()); - }); - - filefield.change(); - - TextButton cancel = new TextButton("$text.cancel"); - cancel.clicked(this::hide); + private void setupWidgets(){ + //getCell(content()).maxWidth(UIUtils.portrait() ? Gdx.graphics.getWidth() : Gdx.graphics.getWidth()/Unit.dp.scl(2f)); + content().margin(-10); - navigation = new TextField(""); - navigation.setTouchable(Touchable.disabled); + Table content = new Table(); - files = new Table(); - files.marginRight(10); - files.marginLeft(3); + filefield = new TextField(); + filefield.setOnlyFontChars(false); + if(!open) Platform.instance.addDialog(filefield); + filefield.setDisabled(open); - pane = new ScrollPane(files){ - public float getPrefHeight(){ - return Gdx.graphics.getHeight(); - } - }; - pane.setOverscroll(false, false); - pane.setFadeScrollBars(false); + ok = new TextButton(open ? "$text.load" : "$text.save"); - updateFiles(true); + ok.clicked(() -> { + if(ok.isDisabled()) return; + if(selectListener != null) + selectListener.accept(directory.child(filefield.getText())); + hide(); + }); - Table icontable = new Table(); - - float isize = 14*2; + filefield.changed(() -> { + ok.setDisabled(filefield.getText().replace(" ", "").isEmpty()); + }); - ImageButton up = new ImageButton("icon-folder-parent"); - up.resizeImage(isize); - up.clicked(()->{ - directory = directory.parent(); - updateFiles(true); - }); + filefield.change(); - //Macs are confined to the Downloads/ directory - if(OS.isMac){ - up.setDisabled(true); - } + TextButton cancel = new TextButton("$text.cancel"); + cancel.clicked(this::hide); - ImageButton back = new ImageButton("icon-arrow-left"); - back.resizeImage(isize); - - ImageButton forward = new ImageButton("icon-arrow-right"); - forward.resizeImage(isize); - - forward.clicked(()-> stack.forward()); - - back.clicked(()-> stack.back()); - - ImageButton home = new ImageButton("icon-home"); - home.resizeImage(isize); - home.clicked(()->{ - directory = homeDirectory; - updateFiles(true); - }); - - icontable.defaults().height(50).growX().uniform(); - icontable.add(home); - icontable.add(back); - icontable.add(forward); - icontable.add(up); - - Table fieldcontent = new Table(); - fieldcontent.bottom().left().add(new Label("File Name:")); - fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f); - - Table buttons = new Table(); - buttons.defaults().growX().height(50); - buttons.add(cancel); - buttons.add(ok); - - content.top().left(); - content.add(icontable).expandX().fillX(); - content.row(); + navigation = new TextField(""); + navigation.setTouchable(Touchable.disabled); - content.center().add(pane).width(UIUtils.portrait() ? Gdx.graphics.getWidth() : Gdx.graphics.getWidth()/Unit.dp.scl(2)).colspan(3).grow(); - content.row(); - - if(!open){ - content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2); - content.row(); - } + files = new Table(); + files.marginRight(10); + files.marginLeft(3); - content.add(buttons).growX(); - - content().add(content); - } - - private void updateFileFieldStatus(){ - if(!open){ - ok.setDisabled(filefield.getText().replace(" ", "").isEmpty()); - }else{ - ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory()); - } - } + pane = new ScrollPane(files){ + public float getPrefHeight(){ + return Gdx.graphics.getHeight(); + } + }; + pane.setOverscroll(false, false); + pane.setFadeScrollBars(false); - private FileHandle[] getFileNames(){ - FileHandle[] handles = directory.list(file -> !file.getName().startsWith(".")); + updateFiles(true); - Arrays.sort(handles, (a, b) ->{ - if(a.isDirectory() && !b.isDirectory()) return -1; - if( !a.isDirectory() && b.isDirectory()) return 1; - return a.name().toUpperCase().compareTo(b.name().toUpperCase()); - }); - return handles; - } + Table icontable = new Table(); - private void updateFiles(boolean push){ - if(push) stack.push(directory); - //if is mac, don't display extra info since you can only ever go to downloads - navigation.setText(OS.isMac ? directory.name() : directory.toString()); - - GlyphLayout layout = Pools.obtain(GlyphLayout.class); - - layout.setText(Core.font, navigation.getText()); - - if(layout.width < navigation.getWidth()){ - navigation.setCursorPosition(0); - }else{ - navigation.setCursorPosition(navigation.getText().length()); - } - - Pools.free(layout); + float isize = 14 * 2; - files.clearChildren(); - files.top().left(); - FileHandle[] names = getFileNames(); + ImageButton up = new ImageButton("icon-folder-parent"); + up.resizeImage(isize); + up.clicked(() -> { + directory = directory.parent(); + updateFiles(true); + }); - //macs are confined to the Downloads/ directory - if(!OS.isMac) { - Image upimage = new Image("icon-folder-parent"); - TextButton upbutton = new TextButton(".." + directory.toString()); - upbutton.clicked(() -> { - directory = directory.parent(); - updateFiles(true); - }); + //Macs are confined to the Downloads/ directory + if(OS.isMac){ + up.setDisabled(true); + } - upbutton.left().add(upimage).padRight(4f).size(14 * 2); - upbutton.getLabel().setAlignment(Align.left); - upbutton.getCells().reverse(); + ImageButton back = new ImageButton("icon-arrow-left"); + back.resizeImage(isize); - files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2); - files.row(); - } - - ButtonGroup group = new ButtonGroup<>(); - group.setMinCheckCount(0); + ImageButton forward = new ImageButton("icon-arrow-right"); + forward.resizeImage(isize); - for(FileHandle file : names){ - if( !file.isDirectory() && !filter.test(file)) continue; //skip non-filtered files + forward.clicked(() -> stack.forward()); - String filename = file.name(); + back.clicked(() -> stack.back()); - TextButton button = new TextButton(shorten(filename), "toggle"); - group.add(button); - - button.clicked(()->{ - if( !file.isDirectory()){ - filefield.setText(filename); - updateFileFieldStatus(); - }else{ - directory = directory.child(filename); - updateFiles(true); - } - }); - - filefield.changed(()->{ - button.setChecked(filename.equals(filefield.getText())); - }); - - Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text"); - - button.add(image).padRight(4f).size(14*2f); - button.getCells().reverse(); - files.top().left().add(button).align(Align.topLeft).fillX().expandX() - .height(50).pad(2).padTop(0).padBottom(0).colspan(2); - button.getLabel().setAlignment(Align.left); - files.row(); - } + ImageButton home = new ImageButton("icon-home"); + home.resizeImage(isize); + home.clicked(() -> { + directory = homeDirectory; + updateFiles(true); + }); - pane.setScrollY(0f); - updateFileFieldStatus(); - - if(open) filefield.clearText(); - } + icontable.defaults().height(50).growX().uniform(); + icontable.add(home); + icontable.add(back); + icontable.add(forward); + icontable.add(up); - private String shorten(String string){ - int max = 30; - if(string.length() <= max){ - return string; - }else{ - return string.substring(0, max - 3).concat("..."); - } - } + Table fieldcontent = new Table(); + fieldcontent.bottom().left().add(new Label("File Name:")); + fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f); - @Override - public Dialog show(){ - Timers.runTask(2f, () -> { - content().clear(); - setupWidgets(); - super.show(); - Core.scene.setScrollFocus(pane); - }); - return this; - } + Table buttons = new Table(); + buttons.defaults().growX().height(50); + buttons.add(cancel); + buttons.add(ok); - public void fileSelected(Consumer listener){ - this.selectListener = listener; - } + content.top().left(); + content.add(icontable).expandX().fillX(); + content.row(); - public class FileHistory{ - private Array history = new Array<>(); - private int index; + content.center().add(pane).width(UIUtils.portrait() ? Gdx.graphics.getWidth() / Unit.dp.scl(1) : Gdx.graphics.getWidth() / Unit.dp.scl(2)).colspan(3).grow(); + content.row(); - public FileHistory(){ + if(!open){ + content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2); + content.row(); + } - } + content.add(buttons).growX(); - public void push(FileHandle file){ - if(index != history.size) history.truncate(index); - history.add(file); - index ++; - } + content().add(content); + } - public void back(){ - if( !canBack()) return; - index --; - directory = history.get(index - 1); - updateFiles(false); - } + private void updateFileFieldStatus(){ + if(!open){ + ok.setDisabled(filefield.getText().replace(" ", "").isEmpty()); + }else{ + ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory()); + } + } - public void forward(){ - if( !canForward()) return; - directory = history.get(index); - index ++; - updateFiles(false); - } + private FileHandle[] getFileNames(){ + FileHandle[] handles = directory.list(file -> !file.getName().startsWith(".")); - public boolean canForward(){ - return !(index >= history.size); - } + Arrays.sort(handles, (a, b) -> { + if(a.isDirectory() && !b.isDirectory()) return -1; + if(!a.isDirectory() && b.isDirectory()) return 1; + return a.name().toUpperCase().compareTo(b.name().toUpperCase()); + }); + return handles; + } - public boolean canBack(){ - return !(index == 1) && index > 0; - } + private void updateFiles(boolean push){ + if(push) stack.push(directory); + //if is mac, don't display extra info since you can only ever go to downloads + navigation.setText(OS.isMac ? directory.name() : directory.toString()); - void print(){ + GlyphLayout layout = Pools.obtain(GlyphLayout.class); - System.out.println("\n\n\n\n\n\n"); - int i = 0; - for(FileHandle file : history){ - i ++; - if(index == i){ - System.out.println("[[" + file.toString() + "]]"); - }else{ - System.out.println("--" + file.toString() + "--"); - } - } - } - } + layout.setText(Core.font, navigation.getText()); - public interface FileHandleFilter{ - boolean accept(FileHandle file); - } + if(layout.width < navigation.getWidth()){ + navigation.setCursorPosition(0); + }else{ + navigation.setCursorPosition(navigation.getText().length()); + } - public static Predicate pngFilter = file -> file.extension().equalsIgnoreCase("png"); - public static Predicate mapFilter = file -> file.extension().equalsIgnoreCase(Vars.mapExtension); - public static Predicate jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg"); - public static Predicate defaultFilter = file -> true; + Pools.free(layout); + + files.clearChildren(); + files.top().left(); + FileHandle[] names = getFileNames(); + + //macs are confined to the Downloads/ directory + if(!OS.isMac){ + Image upimage = new Image("icon-folder-parent"); + TextButton upbutton = new TextButton(".." + directory.toString()); + upbutton.clicked(() -> { + directory = directory.parent(); + updateFiles(true); + }); + + upbutton.left().add(upimage).padRight(4f).size(14 * 2); + upbutton.getLabel().setAlignment(Align.left); + upbutton.getCells().reverse(); + + files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2); + files.row(); + } + + ButtonGroup group = new ButtonGroup<>(); + group.setMinCheckCount(0); + + for(FileHandle file : names){ + if(!file.isDirectory() && !filter.test(file)) continue; //skip non-filtered files + + String filename = file.name(); + + TextButton button = new TextButton(shorten(filename), "toggle"); + group.add(button); + + button.clicked(() -> { + if(!file.isDirectory()){ + filefield.setText(filename); + updateFileFieldStatus(); + }else{ + directory = directory.child(filename); + updateFiles(true); + } + }); + + filefield.changed(() -> { + button.setChecked(filename.equals(filefield.getText())); + }); + + Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text"); + + button.add(image).padRight(4f).size(14 * 2f); + button.getCells().reverse(); + files.top().left().add(button).align(Align.topLeft).fillX().expandX() + .height(50).pad(2).padTop(0).padBottom(0).colspan(2); + button.getLabel().setAlignment(Align.left); + files.row(); + } + + pane.setScrollY(0f); + updateFileFieldStatus(); + + if(open) filefield.clearText(); + } + + private String shorten(String string){ + int max = 30; + if(string.length() <= max){ + return string; + }else{ + return string.substring(0, max - 3).concat("..."); + } + } + + @Override + public Dialog show(){ + Timers.runTask(2f, () -> { + content().clear(); + setupWidgets(); + super.show(); + Core.scene.setScrollFocus(pane); + }); + return this; + } + + public void fileSelected(Consumer listener){ + this.selectListener = listener; + } + + public interface FileHandleFilter{ + boolean accept(FileHandle file); + } + + public class FileHistory{ + private Array history = new Array<>(); + private int index; + + public FileHistory(){ + + } + + public void push(FileHandle file){ + if(index != history.size) history.truncate(index); + history.add(file); + index++; + } + + public void back(){ + if(!canBack()) return; + index--; + directory = history.get(index - 1); + updateFiles(false); + } + + public void forward(){ + if(!canForward()) return; + directory = history.get(index); + index++; + updateFiles(false); + } + + public boolean canForward(){ + return !(index >= history.size); + } + + public boolean canBack(){ + return !(index == 1) && index > 0; + } + + void print(){ + + System.out.println("\n\n\n\n\n\n"); + int i = 0; + for(FileHandle file : history){ + i++; + if(index == i){ + System.out.println("[[" + file.toString() + "]]"); + }else{ + System.out.println("--" + file.toString() + "--"); + } + } + } + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java index e894da9207..16ba45bcff 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java @@ -11,43 +11,43 @@ import io.anuke.ucore.scene.ui.Dialog; import io.anuke.ucore.scene.ui.ScrollPane; public class FloatingDialog extends Dialog{ - - public FloatingDialog(String title){ - super(title, "dialog"); - setFillParent(true); - title().setAlignment(Align.center); - getTitleTable().row(); - getTitleTable().addImage("white", Palette.accent) - .growX().height(3f).pad(4f); - boolean[] done = {false}; + public FloatingDialog(String title){ + super(title, "dialog"); + setFillParent(true); + title().setAlignment(Align.center); + getTitleTable().row(); + getTitleTable().addImage("white", Palette.accent) + .growX().height(3f).pad(4f); - shown(() -> Gdx.app.postRunnable(() -> - forEach(child -> { - if (done[0]) return; + boolean[] done = {false}; - if (child instanceof ScrollPane) { - Core.scene.setScrollFocus(child); - done[0] = true; - } - }))); - } + shown(() -> Gdx.app.postRunnable(() -> + forEach(child -> { + if(done[0]) return; - protected void onResize(Runnable run){ - Events.on(ResizeEvent.class, () -> { - if(isShown()){ - run.run(); - } - }); - } - - @Override - public void addCloseButton(){ - buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f); - - keyDown(key -> { - if(key == Keys.ESCAPE || key == Keys.BACK) - hide(); - }); - } + if(child instanceof ScrollPane){ + Core.scene.setScrollFocus(child); + done[0] = true; + } + }))); + } + + protected void onResize(Runnable run){ + Events.on(ResizeEvent.class, () -> { + if(isShown()){ + run.run(); + } + }); + } + + @Override + public void addCloseButton(){ + buttons().addImageTextButton("$text.back", "icon-arrow-left", 30f, this::hide).size(230f, 64f); + + keyDown(key -> { + if(key == Keys.ESCAPE || key == Keys.BACK) + hide(); + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java index 2864942d46..077cd57de9 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java @@ -55,7 +55,7 @@ public class HostDialog extends FloatingDialog{ try{ Net.host(Vars.port); player.isAdmin = true; - }catch (IOException e){ + }catch(IOException e){ ui.showError(Bundles.format("text.server.error", Strings.parseException(e, false))); } ui.loadfrag.hide(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java index 7777935928..8d48aa37ca 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java @@ -25,7 +25,7 @@ import io.anuke.ucore.util.Strings; import static io.anuke.mindustry.Vars.*; -public class JoinDialog extends FloatingDialog { +public class JoinDialog extends FloatingDialog{ Array servers = new Array<>(); Dialog add; Server renaming; @@ -49,7 +49,7 @@ public class JoinDialog extends FloatingDialog { add = new FloatingDialog("$text.joingame.title"); add.content().add("$text.joingame.ip").padRight(5f).left(); - Platform.instance.addDialog(add.content().addField(Settings.getString("ip"), text ->{ + Platform.instance.addDialog(add.content().addField(Settings.getString("ip"), text -> { Settings.putString("ip", text); Settings.save(); }).size(320f, 54f).get(), 100); @@ -58,7 +58,7 @@ public class JoinDialog extends FloatingDialog { add.buttons().defaults().size(140f, 60f).pad(4f); add.buttons().addButton("$text.cancel", add::hide); add.buttons().addButton("$text.ok", () -> { - if(renaming == null) { + if(renaming == null){ Server server = new Server(Settings.getString("ip"), Strings.parseInt(Settings.getString("port"))); servers.add(server); saveServers(); @@ -88,11 +88,11 @@ public class JoinDialog extends FloatingDialog { void setupRemote(){ remote.clear(); - for (Server server : servers) { + for(Server server : servers){ //why are java lambdas this bad TextButton[] buttons = {null}; - TextButton button = buttons[0] = remote.addButton("[accent]"+server.ip, "clear", () -> { + TextButton button = buttons[0] = remote.addButton("[accent]" + server.ip, "clear", () -> { if(!buttons[0].childrenPressed()) connect(server.ip, Vars.port); }).width(targetWidth()).height(150f).pad(4f).get(); @@ -104,16 +104,16 @@ public class JoinDialog extends FloatingDialog { inner.add(button.getLabel()).growX(); - inner.addImageButton("icon-loading", "empty", 16*2, () -> { + inner.addImageButton("icon-loading", "empty", 16 * 2, () -> { refreshServer(server); }).margin(3f).padTop(6f).top().right(); - inner.addImageButton("icon-pencil", "empty", 16*2, () -> { + inner.addImageButton("icon-pencil", "empty", 16 * 2, () -> { renaming = server; add.show(); }).margin(3f).padTop(6f).top().right(); - inner.addImageButton("icon-trash-16", "empty", 16*2, () -> { + inner.addImageButton("icon-trash-16", "empty", 16 * 2, () -> { ui.showConfirm("$text.confirm", "$text.server.delete", () -> { servers.removeValue(server, true); saveServers(); @@ -124,7 +124,8 @@ public class JoinDialog extends FloatingDialog { button.row(); - server.content = button.table(t -> {}).grow().get(); + server.content = button.table(t -> { + }).grow().get(); remote.row(); } @@ -143,7 +144,7 @@ public class JoinDialog extends FloatingDialog { Net.pingHost(server.ip, server.port, host -> { String versionString; - if(host.version == -1) { + if(host.version == -1){ versionString = Bundles.format("text.server.version", Bundles.get("text.server.custombuild")); }else if(host.version == 0){ versionString = Bundles.get("text.server.outdated"); @@ -179,7 +180,7 @@ public class JoinDialog extends FloatingDialog { } void refreshLocal(){ - if(!Vars.gwt) { + if(!Vars.gwt){ local.clear(); local.background("button"); local.label(() -> "[accent]" + Bundles.get("text.hosts.discovering") + Strings.animated(4, 10f, ".")).pad(10f); @@ -227,7 +228,7 @@ public class JoinDialog extends FloatingDialog { content().row(); content().add(pane).width(w + 34).pad(0); content().row(); - content().addCenteredImageTextButton("$text.server.add", "icon-add", "clear", 14*3, () -> { + content().addCenteredImageTextButton("$text.server.add", "icon-add", "clear", 14 * 3, () -> { renaming = null; add.show(); }).marginLeft(6).width(w).height(80f).update(button -> { @@ -238,7 +239,7 @@ public class JoinDialog extends FloatingDialog { pad = 6; } - Cell cell = ((Table)pane.getParent()).getCell(button); + Cell cell = ((Table) pane.getParent()).getCell(button); if(!MathUtils.isEqual(cell.getMinWidth(), pw)){ cell.width(pw); @@ -256,10 +257,10 @@ public class JoinDialog extends FloatingDialog { if(array.size == 0){ local.add("$text.hosts.none").pad(10f); local.add().growX(); - local.addImageButton("icon-loading", 16*2f, this::refreshLocal).pad(-10f).padLeft(0).padTop(-6).size(70f, 74f); - }else { - for (Host a : array) { - TextButton button = local.addButton("[accent]"+a.name, "clear", () -> { + local.addImageButton("icon-loading", 16 * 2f, this::refreshLocal).pad(-10f).padLeft(0).padTop(-6).size(70f, 74f); + }else{ + for(Host a : array){ + TextButton button = local.addButton("[accent]" + a.name, "clear", () -> { connect(a.address, Vars.port); }).width(w).height(80f).pad(4f).get(); button.left(); @@ -289,18 +290,18 @@ public class JoinDialog extends FloatingDialog { Net.connect(ip, port); hide(); add.hide(); - }catch (Exception e) { + }catch(Exception e){ Throwable t = e; while(t.getCause() != null){ t = t.getCause(); } //TODO localize String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); - if(error.contains("connection refused")) { + if(error.contains("connection refused")){ error = "connection refused"; }else if(error.contains("port out of range")){ error = "invalid port!"; - }else if(error.contains("invalid argument")) { + }else if(error.contains("invalid argument")){ error = "invalid IP or port!"; }else if(t.getClass().toString().toLowerCase().contains("sockettimeout")){ error = "timed out!\nmake sure the host has port forwarding set up,\nand that the address is correct!"; @@ -340,6 +341,7 @@ public class JoinDialog extends FloatingDialog { this.port = port; } - Server(){} + Server(){ + } } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LevelDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LevelDialog.java index 457856f17c..4df4316cd7 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LevelDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LevelDialog.java @@ -24,142 +24,142 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; public class LevelDialog extends FloatingDialog{ - - public LevelDialog(){ - super("$text.level.select"); - addCloseButton(); - shown(this::setup); - onResize(this::setup); - } - - void setup(){ - content().clear(); + public LevelDialog(){ + super("$text.level.select"); + addCloseButton(); + shown(this::setup); - Table maps = new Table(); - maps.marginRight(14); - ScrollPane pane = new ScrollPane(maps, "clear-black"); - pane.setFadeScrollBars(false); - - int maxwidth = (Gdx.graphics.getHeight() > Gdx.graphics.getHeight() ? 2 : 4); - - Table selmode = new Table(); - ButtonGroup group = new ButtonGroup<>(); - selmode.add("$text.level.mode").padRight(15f); - - for(GameMode mode : GameMode.values()){ - TextButton[] b = {null}; - b[0] = Elements.newButton("$mode." + mode.name() + ".name", "toggle", () -> state.mode = mode); - b[0].update(() -> b[0].setChecked(state.mode == mode)); - group.add(b[0]); - selmode.add(b[0]).size(130f, 54f); - } - selmode.addButton("?", this::displayGameModeHelp).size(50f, 54f).padLeft(18f); - - content().add(selmode); - content().row(); + onResize(this::setup); + } - Difficulty[] ds = Difficulty.values(); + void setup(){ + content().clear(); - float s = 50f; + Table maps = new Table(); + maps.marginRight(14); + ScrollPane pane = new ScrollPane(maps, "clear-black"); + pane.setFadeScrollBars(false); - Table sdif = new Table(); + int maxwidth = (Gdx.graphics.getHeight() > Gdx.graphics.getHeight() ? 2 : 4); - sdif.add("$setting.difficulty.name").padRight(15f); + Table selmode = new Table(); + ButtonGroup group = new ButtonGroup<>(); + selmode.add("$text.level.mode").padRight(15f); - sdif.defaults().height(s+4); - sdif.addImageButton("icon-arrow-left", 10*3, () -> { - state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() - 1, ds.length)]); - }).width(s); + for(GameMode mode : GameMode.values()){ + TextButton[] b = {null}; + b[0] = Elements.newButton("$mode." + mode.name() + ".name", "toggle", () -> state.mode = mode); + b[0].update(() -> b[0].setChecked(state.mode == mode)); + group.add(b[0]); + selmode.add(b[0]).size(130f, 54f); + } + selmode.addButton("?", this::displayGameModeHelp).size(50f, 54f).padLeft(18f); - sdif.addButton("", () -> { + content().add(selmode); + content().row(); - }).update(t -> { - t.setText(state.difficulty.toString()); - t.setTouchable(Touchable.disabled); - }).width(180f); + Difficulty[] ds = Difficulty.values(); - sdif.addImageButton("icon-arrow-right", 10*3, () -> { - state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() + 1, ds.length)]); - }).width(s); + float s = 50f; - content().add(sdif); - content().row(); + Table sdif = new Table(); - float images = 146f; + sdif.add("$setting.difficulty.name").padRight(15f); - int i = 0; - for(Map map : world.maps().all()){ + sdif.defaults().height(s + 4); + sdif.addImageButton("icon-arrow-left", 10 * 3, () -> { + state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() - 1, ds.length)]); + }).width(s); - if(i % maxwidth == 0){ - maps.row(); - } - - ImageButton image = new ImageButton(new TextureRegion(map.texture), "clear"); - image.margin(5); - image.getImageCell().size(images); - image.top(); - image.row(); - image.add("[accent]" + Bundles.get("map."+map.name+".name", map.name)).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center); - image.row(); - image.label((() -> Bundles.format("text.level.highscore", Settings.getInt("hiscore" + map.name, 0)))).pad(3f); + sdif.addButton("", () -> { - BorderImage border = new BorderImage(map.texture, 3f); - image.replaceImage(border); + }).update(t -> { + t.setText(state.difficulty.toString()); + t.setTouchable(Touchable.disabled); + }).width(180f); - image.clicked(() -> { - hide(); - control.playMap(map); - }); - - maps.add(image).width(170).fillY().top().pad(4f); - - i ++; - } + sdif.addImageButton("icon-arrow-right", 10 * 3, () -> { + state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() + 1, ds.length)]); + }).width(s); - ImageButton genb = maps.addImageButton("icon-editor", "clear", 16*3, () -> { - hide(); + content().add(sdif); + content().row(); - ui.loadfrag.show(); + float images = 146f; - Timers.run(5f, () -> { - Cursors.restoreCursor(); - threads.run(() -> { - world.loadProceduralMap(); - logic.play(); - Gdx.app.postRunnable(ui.loadfrag::hide); - }); - }); - }).width(170).fillY().pad(4f).get(); + int i = 0; + for(Map map : world.maps().all()){ - genb.top(); - genb.margin(5); - genb.clearChildren(); - genb.add(new BorderImage(Draw.region("icon-generated"), 3f)).size(images); - genb.row(); - genb.add("$text.map.random").growX().wrap().pad(3f).get().setAlignment(Align.center, Align.center); - genb.row(); - genb.add("").pad(3f); - - content().add(pane).uniformX(); - } + if(i % maxwidth == 0){ + maps.row(); + } - private void displayGameModeHelp() { - FloatingDialog d = new FloatingDialog(Bundles.get("mode.text.help.title")); - d.setFillParent(false); - Table table = new Table(); - table.defaults().pad(1f); - ScrollPane pane = new ScrollPane(table, "clear"); - pane.setFadeScrollBars(false); - table.row(); - for(GameMode mode : GameMode.values()){ - table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(600f); - table.row(); - } + ImageButton image = new ImageButton(new TextureRegion(map.texture), "clear"); + image.margin(5); + image.getImageCell().size(images); + image.top(); + image.row(); + image.add("[accent]" + Bundles.get("map." + map.name + ".name", map.name)).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center); + image.row(); + image.label((() -> Bundles.format("text.level.highscore", Settings.getInt("hiscore" + map.name, 0)))).pad(3f); - d.content().add(pane); - d.buttons().addButton("$text.ok", d::hide).size(110, 50).pad(10f); - d.show(); - } + BorderImage border = new BorderImage(map.texture, 3f); + image.replaceImage(border); + + image.clicked(() -> { + hide(); + control.playMap(map); + }); + + maps.add(image).width(170).fillY().top().pad(4f); + + i++; + } + + ImageButton genb = maps.addImageButton("icon-editor", "clear", 16 * 3, () -> { + hide(); + + ui.loadfrag.show(); + + Timers.run(5f, () -> { + Cursors.restoreCursor(); + threads.run(() -> { + world.loadProceduralMap(); + logic.play(); + Gdx.app.postRunnable(ui.loadfrag::hide); + }); + }); + }).width(170).fillY().pad(4f).get(); + + genb.top(); + genb.margin(5); + genb.clearChildren(); + genb.add(new BorderImage(Draw.region("icon-generated"), 3f)).size(images); + genb.row(); + genb.add("$text.map.random").growX().wrap().pad(3f).get().setAlignment(Align.center, Align.center); + genb.row(); + genb.add("").pad(3f); + + content().add(pane).uniformX(); + } + + private void displayGameModeHelp(){ + FloatingDialog d = new FloatingDialog(Bundles.get("mode.text.help.title")); + d.setFillParent(false); + Table table = new Table(); + table.defaults().pad(1f); + ScrollPane pane = new ScrollPane(table, "clear"); + pane.setFadeScrollBars(false); + table.row(); + for(GameMode mode : GameMode.values()){ + table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(600f); + table.row(); + } + + d.content().add(pane); + d.buttons().addButton("$text.ok", d::hide).size(110, 50).pad(10f); + d.show(); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java index 7285338725..529c48ff73 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java @@ -6,11 +6,9 @@ import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.Platform; -import io.anuke.mindustry.game.EventType.ResizeEvent; import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.io.Saves.SaveSlot; import io.anuke.ucore.core.Core; -import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Timers; import io.anuke.ucore.scene.ui.ScrollPane; import io.anuke.ucore.scene.ui.TextButton; @@ -24,174 +22,177 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; public class LoadDialog extends FloatingDialog{ - ScrollPane pane; - Table slots; + ScrollPane pane; + Table slots; - public LoadDialog() { - this("$text.loadgame"); - } + public LoadDialog(){ + this("$text.loadgame"); + } - public LoadDialog(String title) { - super(title); - setup(); + public LoadDialog(String title){ + super(title); + setup(); - shown(() -> { - setup(); - Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane)); - }); + shown(() -> { + setup(); + Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane)); + }); - addCloseButton(); - } + addCloseButton(); + } - protected void setup(){ - content().clear(); + protected void setup(){ + content().clear(); - slots = new Table(); - pane = new ScrollPane(slots, "clear-black"); - pane.setFadeScrollBars(false); - pane.setScrollingDisabled(true, false); + slots = new Table(); + pane = new ScrollPane(slots, "clear-black"); + pane.setFadeScrollBars(false); + pane.setScrollingDisabled(true, false); - slots.marginRight(24); + slots.marginRight(24); - Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane)); + Timers.runTask(2f, () -> Core.scene.setScrollFocus(pane)); - Array array = control.getSaves().getSaveSlots(); + Array array = control.getSaves().getSaveSlots(); - for(SaveSlot slot : array){ + for(SaveSlot slot : array){ - TextButton button = new TextButton("[accent]" + slot.getName(), "clear"); - button.getLabelCell().growX().left(); - button.getLabelCell().padBottom(8f); - button.getLabelCell().top().left().growX(); + TextButton button = new TextButton("[accent]" + slot.getName(), "clear"); + button.getLabelCell().growX().left(); + button.getLabelCell().padBottom(8f); + button.getLabelCell().top().left().growX(); - button.defaults().left(); + button.defaults().left(); - button.table(t -> { - t.right(); + button.table(t -> { + t.right(); - t.addImageButton("icon-floppy", "emptytoggle", 14*3, () -> { - slot.setAutosave(!slot.isAutosave()); - }).checked(slot.isAutosave()).right(); + t.addImageButton("icon-floppy", "emptytoggle", 14 * 3, () -> { + slot.setAutosave(!slot.isAutosave()); + }).checked(slot.isAutosave()).right(); - t.addImageButton("icon-trash", "empty", 14*3, () -> { - ui.showConfirm("$text.confirm", "$text.save.delete.confirm", () -> { - slot.delete(); - setup(); - }); - }).size(14*3).right(); + t.addImageButton("icon-trash", "empty", 14 * 3, () -> { + ui.showConfirm("$text.confirm", "$text.save.delete.confirm", () -> { + slot.delete(); + setup(); + }); + }).size(14 * 3).right(); - t.addImageButton("icon-pencil-small", "empty", 14*3, () -> { - ui.showTextInput("$text.save.rename", "$text.save.rename.text", slot.getName(), text -> { - slot.setName(text); - setup(); - }); - }).size(14*3).right(); + t.addImageButton("icon-pencil-small", "empty", 14 * 3, () -> { + ui.showTextInput("$text.save.rename", "$text.save.rename.text", slot.getName(), text -> { + slot.setName(text); + setup(); + }); + }).size(14 * 3).right(); - if(!gwt) { - t.addImageButton("icon-save", "empty", 14 * 3, () -> { - if(!ios) { - Platform.instance.showFileChooser(Bundles.get("text.save.export"), "Mindustry Save", file -> { - try { - slot.exportFile(file); - setup(); - } catch (IOException e) { - ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false))); - } - }, false, saveExtension); + if(!gwt){ + t.addImageButton("icon-save", "empty", 14 * 3, () -> { + if(!ios){ + Platform.instance.showFileChooser(Bundles.get("text.save.export"), "Mindustry Save", file -> { + try{ + slot.exportFile(file); + setup(); + }catch(IOException e){ + ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false))); + } + }, false, saveExtension); }else{ - try { + try{ FileHandle file = Gdx.files.local("save-" + slot.getName() + "." + Vars.saveExtension); slot.exportFile(file); Platform.instance.shareFile(file); - }catch (Exception e){ + }catch(Exception e){ ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false))); } } - }).size(14 * 3).right(); - } + }).size(14 * 3).right(); + } - }).padRight(-10).growX(); + }).padRight(-10).growX(); - String color = "[lightgray]"; + String color = "[lightgray]"; - button.defaults().padBottom(3); - button.row(); - button.add(Bundles.format("text.save.map", color+ (slot.getMap() == null ? "Unknown" : slot.getMap().meta.name()))); - button.row(); - button.add(Bundles.get("text.level.mode") + " " +color+ slot.getMode()); - button.row(); - button.add(Bundles.format("text.save.wave", color+slot.getWave())); - button.row(); - button.add(Bundles.format("text.save.difficulty", color+slot.getDifficulty())); - button.row(); - button.label(() -> Bundles.format("text.save.autosave", color + Bundles.get(slot.isAutosave() ? "text.on" : "text.off"))); - button.row(); - button.add(Bundles.format("text.save.date", color+slot.getDate())).colspan(2).padTop(5).right(); - button.row(); - modifyButton(button, slot); + button.defaults().padBottom(3); + button.row(); + button.add(Bundles.format("text.save.map", color + (slot.getMap() == null ? "Unknown" : slot.getMap().meta.name()))); + button.row(); + button.add(Bundles.get("text.level.mode") + " " + color + slot.getMode()); + button.row(); + button.add(Bundles.format("text.save.wave", color + slot.getWave())); + button.row(); + button.add(Bundles.format("text.save.difficulty", color + slot.getDifficulty())); + button.row(); + button.label(() -> Bundles.format("text.save.autosave", color + Bundles.get(slot.isAutosave() ? "text.on" : "text.off"))); + button.row(); + button.add(Bundles.format("text.save.date", color + slot.getDate())).colspan(2).padTop(5).right(); + button.row(); + modifyButton(button, slot); - slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).marginLeft(20f).marginRight(20f); - slots.row(); - } + slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).marginLeft(20f).marginRight(20f); + slots.row(); + } - content().add(pane); + content().add(pane); - addSetup(); - } + addSetup(); + } - public void addSetup(){ - if(control.getSaves().getSaveSlots().size == 0) { + public void addSetup(){ + if(control.getSaves().getSaveSlots().size == 0){ - slots.row(); - slots.addButton("$text.save.none", "clear", () -> { - }).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f); - } + slots.row(); + slots.addButton("$text.save.none", "clear", () -> { + }).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f); + } - slots.row(); + slots.row(); - if(gwt || ios) return; + if(gwt || ios) return; - slots.addImageTextButton("$text.save.import", "icon-add", "clear", 14*3, () -> { - Platform.instance.showFileChooser(Bundles.get("text.save.import"), "Mindustry Save", file -> { - if(SaveIO.isSaveValid(file)){ - try{ - control.getSaves().importSave(file); - setup(); - }catch (IOException e){ - ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false))); - } - }else{ - ui.showError("$text.save.import.invalid"); - } - }, true, saveExtension); - }).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); - } + slots.addImageTextButton("$text.save.import", "icon-add", "clear", 14 * 3, () -> { + Platform.instance.showFileChooser(Bundles.get("text.save.import"), "Mindustry Save", file -> { + if(SaveIO.isSaveValid(file)){ + try{ + control.getSaves().importSave(file); + setup(); + }catch(IOException e){ + ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false))); + } + }else{ + ui.showError("$text.save.import.invalid"); + } + }, true, saveExtension); + }).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); + } - public void runLoadSave(SaveSlot slot){ - ui.loadfrag.show(); + public void runLoadSave(SaveSlot slot){ + hide(); + ui.paused.hide(); - Timers.runTask(3f, () -> { - ui.loadfrag.hide(); - hide(); + ui.loadLogic(() -> { try{ slot.load(); state.set(State.playing); - ui.paused.hide(); }catch(Exception e){ Log.err(e); - ui.paused.hide(); state.set(State.menu); logic.reset(); - ui.showError("$text.save.corrupted"); + threads.runGraphics(() -> ui.showError("$text.save.corrupted")); } }); } - public void modifyButton(TextButton button, SaveSlot slot){ - button.clicked(() -> { - if(!button.childrenPressed()){ - runLoadSave(slot); - } - }); - } + public void modifyButton(TextButton button, SaveSlot slot){ + button.clicked(() -> { + if(!button.childrenPressed()){ + int build = slot.getBuild(); + if(SaveIO.breakingVersions.contains(build)){ + ui.showInfo("$text.save.old"); + slot.delete(); + }else{ + runLoadSave(slot); + } + } + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java index 29927af5b4..7ef5786ee3 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java @@ -1,16 +1,18 @@ package io.anuke.mindustry.ui.dialogs; import com.badlogic.gdx.utils.Scaling; -import static io.anuke.mindustry.Vars.*; import io.anuke.mindustry.entities.Player; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.layout.Stack; import io.anuke.ucore.scene.ui.layout.Table; +import static io.anuke.mindustry.Vars.control; +import static io.anuke.mindustry.Vars.players; + public class LocalPlayerDialog extends FloatingDialog{ - public LocalPlayerDialog() { + public LocalPlayerDialog(){ super("$text.addplayers"); addCloseButton(); @@ -22,7 +24,7 @@ public class LocalPlayerDialog extends FloatingDialog{ content().clear(); - if(players.length > 1) { + if(players.length > 1){ content().addImageButton("icon-cancel", 14 * 2, () -> { control.removePlayer(); rebuild(); @@ -49,7 +51,7 @@ public class LocalPlayerDialog extends FloatingDialog{ content().add(table).pad(5); } - if(players.length < 4) { + if(players.length < 4){ content().addImageButton("icon-add", 14 * 2, () -> { control.addPlayer(players.length); rebuild(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index f1abf8086c..b60603fa82 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -22,13 +22,13 @@ import java.io.DataInputStream; import static io.anuke.mindustry.Vars.*; -public class MapsDialog extends FloatingDialog { +public class MapsDialog extends FloatingDialog{ - public MapsDialog() { + public MapsDialog(){ super("$text.maps"); addCloseButton(); - buttons().addImageTextButton("$text.editor.importmap", "icon-add", 14*2, () -> { + buttons().addImageTextButton("$text.editor.importmap", "icon-add", 14 * 2, () -> { Platform.instance.showFileChooser("$text.editor.importmap", "Map File", file -> { try{ DataInputStream stream = new DataInputStream(file.read()); @@ -50,7 +50,7 @@ public class MapsDialog extends FloatingDialog { setup(); } - }catch (Exception e){ + }catch(Exception e){ ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false))); Log.err(e); } @@ -86,11 +86,11 @@ public class MapsDialog extends FloatingDialog { button.row(); button.addImage("white").growX().pad(4).color(Color.GRAY); button.row(); - ((Image)button.stack(new Image(map.texture), new BorderImage(map.texture)).size(mapsize-20f).get().getChildren().first()).setScaling(Scaling.fit); + ((Image) button.stack(new Image(map.texture), new BorderImage(map.texture)).size(mapsize - 20f).get().getChildren().first()).setScaling(Scaling.fit); button.row(); button.add(map.custom ? "$text.custom" : "$text.builtin").color(Color.GRAY).padTop(3); - i ++; + i++; } if(world.maps().all().size == 0){ @@ -139,13 +139,13 @@ public class MapsDialog extends FloatingDialog { table.row(); - table.addImageTextButton("$text.editor.openin", "icon-load-map", "clear", 16*2, () -> { + table.addImageTextButton("$text.editor.openin", "icon-load-map", "clear", 16 * 2, () -> { Vars.ui.editor.beginEditMap(map.stream.get()); dialog.hide(); hide(); }).fillX().height(50f).marginLeft(6); - table.addImageTextButton("$text.delete", "icon-trash-16", "clear", 16*2, () -> { + table.addImageTextButton("$text.delete", "icon-trash-16", "clear", 16 * 2, () -> { ui.showConfirm("$text.confirm", Bundles.format("text.map.delete", map.name), () -> { world.maps().removeMap(map); dialog.hide(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java index 5caf0f519b..a517f2894c 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java @@ -1,9 +1,7 @@ package io.anuke.mindustry.ui.dialogs; -import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.net.Net; -import io.anuke.ucore.core.Timers; import io.anuke.ucore.scene.builders.build; import io.anuke.ucore.scene.builders.imagebutton; import io.anuke.ucore.util.Bundles; @@ -11,136 +9,133 @@ import io.anuke.ucore.util.Bundles; import static io.anuke.mindustry.Vars.*; public class PausedDialog extends FloatingDialog{ - private SaveDialog save = new SaveDialog(); - private LoadDialog load = new LoadDialog(); - public boolean wasPaused = false; + public boolean wasPaused = false; + private SaveDialog save = new SaveDialog(); + private LoadDialog load = new LoadDialog(); - public PausedDialog() { - super("$text.menu"); - setup(); - } + public PausedDialog(){ + super("$text.menu"); + setup(); + } - void setup(){ - update(() -> { - if(state.is(State.menu) && isShown()){ - hide(); - } - }); + void setup(){ + update(() -> { + if(state.is(State.menu) && isShown()){ + hide(); + } + }); - shown(() -> { - wasPaused = state.is(State.paused); - if(!Net.active()) state.set(State.paused); - }); - - if(!mobile){ - content().defaults().width(220).height(50); + shown(() -> { + wasPaused = state.is(State.paused); + if(!Net.active()) state.set(State.paused); + }); - content().addButton("$text.back", () -> { - hide(); - if((!wasPaused || Net.active()) && !state.is(State.menu)) - state.set(State.playing); - }); + if(!mobile){ + content().defaults().width(220).height(50); - content().row(); - content().addButton("$text.settings", ui.settings::show); + content().addButton("$text.back", () -> { + hide(); + if((!wasPaused || Net.active()) && !state.is(State.menu)) + state.set(State.playing); + }); - content().row(); - content().addButton("$text.savegame", () -> { - save.show(); - }); + content().row(); + content().addButton("$text.settings", ui.settings::show); - content().row(); - content().addButton("$text.loadgame", () -> { - load.show(); - }).disabled(b -> Net.active()); + content().row(); + content().addButton("$text.savegame", () -> { + save.show(); + }); - //Local multiplayer is currently functional, but disabled. + content().row(); + content().addButton("$text.loadgame", () -> { + load.show(); + }).disabled(b -> Net.active()); + + //Local multiplayer is currently functional, but disabled. /* content().row(); content().addButton("$text.addplayers", () -> { ui.localplayers.show(); }).disabled(b -> Net.active());*/ - content().row(); + content().row(); - content().addButton("$text.hostserver", () -> { - if(!gwt){ - ui.host.show(); - }else{ - ui.showInfo("$text.host.web"); - } - }).disabled(b -> Net.active()); + content().addButton("$text.hostserver", () -> { + if(!gwt){ + ui.host.show(); + }else{ + ui.showInfo("$text.host.web"); + } + }).disabled(b -> Net.active()); content().row(); - content().addButton("$text.quit", () -> { + content().addButton("$text.quit", () -> { ui.showConfirm("$text.confirm", "$text.quit.confirm", () -> { - if(Net.client()) netClient.disconnectQuietly(); - runExitSave(); - hide(); - }); - }); + if(Net.client()) netClient.disconnectQuietly(); + runExitSave(); + hide(); + }); + }); - }else{ - build.begin(content()); - - content().defaults().size(120f).pad(5); - float isize = 14f*4; - - new imagebutton("icon-play-2", isize, () -> { - hide(); - if(!wasPaused && !state.is(State.menu)) - state.set(State.playing); - }).text("$text.back").padTop(4f); - - new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f); - - imagebutton sa = new imagebutton("icon-save", isize, save::show); - sa.text("$text.save").padTop(4f); + }else{ + build.begin(content()); - content().row(); - - imagebutton lo = new imagebutton("icon-load", isize, load::show); - lo.text("$text.load").padTop(4f); - lo.cell.disabled(b -> Net.active()); + content().defaults().size(120f).pad(5); + float isize = 14f * 4; - imagebutton ho = new imagebutton("icon-host", isize, () -> { - ui.host.show(); - }); - ho.text("$text.host").padTop(4f); - ho.cell.disabled(b -> Net.active()); - - new imagebutton("icon-quit", isize, () -> { - ui.showConfirm("$text.confirm", "$text.quit.confirm", () -> { - if(Net.client()) netClient.disconnectQuietly(); - runExitSave(); - hide(); - }); - }).text("Quit").padTop(4f); - - build.end(); - } - } + new imagebutton("icon-play-2", isize, () -> { + hide(); + if(!wasPaused && !state.is(State.menu)) + state.set(State.playing); + }).text("$text.back").padTop(4f); - private void runExitSave(){ - if(control.getSaves().getCurrent() == null || - !control.getSaves().getCurrent().isAutosave()){ - state.set(State.menu); - return; - } + new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f); - ui.loadfrag.show("$text.saveload"); + imagebutton sa = new imagebutton("icon-save", isize, save::show); + sa.text("$text.save").padTop(4f); - Timers.runTask(5f, () -> { - ui.loadfrag.hide(); - try{ - control.getSaves().getCurrent().save(); - }catch(Throwable e){ - e = (e.getCause() == null ? e : e.getCause()); - ui.showError("[orange]"+ Bundles.get("text.savefail")+"\n[white]" + ClassReflection.getSimpleName(e.getClass()) + ": " + e.getMessage() + "\n" + "at " + e.getStackTrace()[0].getFileName() + ":" + e.getStackTrace()[0].getLineNumber()); - } - state.set(State.menu); - }); - } + content().row(); + + imagebutton lo = new imagebutton("icon-load", isize, load::show); + lo.text("$text.load").padTop(4f); + lo.cell.disabled(b -> Net.active()); + + imagebutton ho = new imagebutton("icon-host", isize, () -> { + ui.host.show(); + }); + ho.text("$text.host").padTop(4f); + ho.cell.disabled(b -> Net.active()); + + new imagebutton("icon-quit", isize, () -> { + ui.showConfirm("$text.confirm", "$text.quit.confirm", () -> { + if(Net.client()) netClient.disconnectQuietly(); + runExitSave(); + hide(); + }); + }).text("Quit").padTop(4f); + + build.end(); + } + } + + private void runExitSave(){ + if(control.getSaves().getCurrent() == null || + !control.getSaves().getCurrent().isAutosave()){ + state.set(State.menu); + return; + } + + ui.loadLogic("$text.saveload", () -> { + try{ + control.getSaves().getCurrent().save(); + }catch(Throwable e){ + e.printStackTrace(); + threads.runGraphics(() -> ui.showError("[orange]" + Bundles.get("text.savefail"))); + } + state.set(State.menu); + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/RestartDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/RestartDialog.java index 855f53d6ff..38554f889f 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/RestartDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/RestartDialog.java @@ -5,8 +5,8 @@ import io.anuke.ucore.scene.ui.Dialog; import static io.anuke.mindustry.Vars.*; -public class RestartDialog extends Dialog { - +public class RestartDialog extends Dialog{ + public RestartDialog(){ super("$text.gameover", "dialog"); @@ -21,7 +21,7 @@ public class RestartDialog extends Dialog { pack(); }); - getButtonTable().addButton("$text.menu", ()-> { + getButtonTable().addButton("$text.menu", () -> { hide(); state.set(State.menu); logic.reset(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java index 9675e64a9c..2a991e30dd 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java @@ -5,34 +5,35 @@ import io.anuke.ucore.util.Strings; import static io.anuke.mindustry.Vars.gwt; -public class RollbackDialog extends FloatingDialog { - - public RollbackDialog(){ - super("$text.server.rollback"); - - setup(); - shown(this::setup); - } - - private void setup(){ - content().clear(); - buttons().clear(); - - if(gwt) return; - - content().row(); - content().add("$text.server.rollback.numberfield"); - - TextField field = content().addField("", t->{}).size(200f, 48f).get(); - field.setTextFieldFilter((f, c) -> field.getText().length() < 4); - - content().row(); - buttons().defaults().size(200f, 50f).left().pad(2f); - buttons().addButton("$text.cancel", this::hide); - - buttons().addButton("$text.ok", () -> { - //NetEvents.handleRollbackRequest(Integer.valueOf(field.getText())); - hide(); - }).disabled(b -> field.getText().isEmpty() || !Strings.canParsePostiveInt(field.getText())); - } +public class RollbackDialog extends FloatingDialog{ + + public RollbackDialog(){ + super("$text.server.rollback"); + + setup(); + shown(this::setup); + } + + private void setup(){ + content().clear(); + buttons().clear(); + + if(gwt) return; + + content().row(); + content().add("$text.server.rollback.numberfield"); + + TextField field = content().addField("", t -> { + }).size(200f, 48f).get(); + field.setTextFieldFilter((f, c) -> field.getText().length() < 4); + + content().row(); + buttons().defaults().size(200f, 50f).left().pad(2f); + buttons().addButton("$text.cancel", this::hide); + + buttons().addButton("$text.ok", () -> { + //NetEvents.handleRollbackRequest(Integer.valueOf(field.getText())); + hide(); + }).disabled(b -> field.getText().isEmpty() || !Strings.canParsePostiveInt(field.getText())); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java index f56b6f3137..26a5e6b148 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java @@ -11,57 +11,57 @@ import static io.anuke.mindustry.Vars.*; public class SaveDialog extends LoadDialog{ - public SaveDialog() { - super("$text.savegame"); + public SaveDialog(){ + super("$text.savegame"); - update(() -> { - if(state.is(State.menu) && isShown()){ - hide(); - } - }); - } + update(() -> { + if(state.is(State.menu) && isShown()){ + hide(); + } + }); + } - public void addSetup(){ - if(!control.getSaves().canAddSave()){ - return; - } + public void addSetup(){ + if(!control.getSaves().canAddSave()){ + return; + } - slots.row(); - slots.addImageTextButton("$text.save.new", "icon-add", "clear", 14*3, () -> - ui.showTextInput("$text.save", "$text.save.newslot", "", text -> { - ui.loadAnd("$text.saving", () -> { - control.getSaves().addSave(text); - setup(); - }); - }) - ).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); - } + slots.row(); + slots.addImageTextButton("$text.save.new", "icon-add", "clear", 14 * 3, () -> + ui.showTextInput("$text.save", "$text.save.newslot", "", text -> { + ui.loadAnd("$text.saving", () -> { + control.getSaves().addSave(text); + setup(); + }); + }) + ).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); + } - @Override - public void modifyButton(TextButton button, SaveSlot slot){ - button.clicked(() -> { - if(button.childrenPressed()) return; + @Override + public void modifyButton(TextButton button, SaveSlot slot){ + button.clicked(() -> { + if(button.childrenPressed()) return; - ui.showConfirm("$text.overwrite", "$text.save.overwrite", () -> save(slot)); - }); - } + ui.showConfirm("$text.overwrite", "$text.save.overwrite", () -> save(slot)); + }); + } - void save(SaveSlot slot){ + void save(SaveSlot slot){ - ui.loadfrag.show("$text.saveload"); + ui.loadfrag.show("$text.saveload"); - Timers.runTask(5f, () -> { - hide(); - ui.loadfrag.hide(); - try{ - slot.save(); - }catch(Throwable e){ - e.printStackTrace(); - e = (e.getCause() == null ? e : e.getCause()); + Timers.runTask(5f, () -> { + hide(); + ui.loadfrag.hide(); + try{ + slot.save(); + }catch(Throwable e){ + e.printStackTrace(); + e = (e.getCause() == null ? e : e.getCause()); - ui.showError("[orange]"+Bundles.get("text.savefail")+"\n[white]" + ClassReflection.getSimpleName(e.getClass()) + ": " + e.getMessage() + "\n" + "at " + e.getStackTrace()[0].getFileName() + ":" + e.getStackTrace()[0].getLineNumber()); - } - }); - } + ui.showError("[orange]" + Bundles.get("text.savefail") + "\n[white]" + ClassReflection.getSimpleName(e.getClass()) + ": " + e.getMessage() + "\n" + "at " + e.getStackTrace()[0].getFileName() + ":" + e.getStackTrace()[0].getLineNumber()); + } + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 72ebfe9ccb..a1fc7bbc3f 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -24,164 +24,164 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; public class SettingsMenuDialog extends SettingsDialog{ - public SettingsTable graphics; - public SettingsTable game; - public SettingsTable sound; + public SettingsTable graphics; + public SettingsTable game; + public SettingsTable sound; - private Table prefs; - private Table menu; - private boolean wasPaused; - - public SettingsMenuDialog(){ - setStyle(Core.skin.get("dialog", WindowStyle.class)); + private Table prefs; + private Table menu; + private boolean wasPaused; - hidden(() -> { - if(!state.is(State.menu)){ - if(!wasPaused || Net.active()) - state.set(State.playing); - } - }); + public SettingsMenuDialog(){ + setStyle(Core.skin.get("dialog", WindowStyle.class)); - shown(() -> { - if(!state.is(State.menu)){ - wasPaused = state.is(State.paused); - if(ui.paused.getScene() != null){ - wasPaused = ui.paused.wasPaused; - } - if(!Net.active()) state.set(State.paused); - ui.paused.hide(); - } - }); + hidden(() -> { + if(!state.is(State.menu)){ + if(!wasPaused || Net.active()) + state.set(State.playing); + } + }); - setFillParent(true); - title().setAlignment(Align.center); - getTitleTable().row(); - getTitleTable().add(new Image("white")) - .growX().height(3f).pad(4f).get().setColor(Palette.accent); + shown(() -> { + if(!state.is(State.menu)){ + wasPaused = state.is(State.paused); + if(ui.paused.getScene() != null){ + wasPaused = ui.paused.wasPaused; + } + if(!Net.active()) state.set(State.paused); + ui.paused.hide(); + } + }); - content().clearChildren(); - content().remove(); - buttons().remove(); + setFillParent(true); + title().setAlignment(Align.center); + getTitleTable().row(); + getTitleTable().add(new Image("white")) + .growX().height(3f).pad(4f).get().setColor(Palette.accent); - menu = new Table(); + content().clearChildren(); + content().remove(); + buttons().remove(); - Consumer s = table -> { - table.row(); - table.addImageTextButton("$text.back", "icon-arrow-left", 10*3, this::back).size(240f, 60f).colspan(2).padTop(15f); - }; + menu = new Table(); - game = new SettingsTable(s); - graphics = new SettingsTable(s); - sound = new SettingsTable(s); + Consumer s = table -> { + table.row(); + table.addImageTextButton("$text.back", "icon-arrow-left", 10 * 3, this::back).size(240f, 60f).colspan(2).padTop(15f); + }; - prefs = new Table(); - prefs.top(); - prefs.margin(14f); + game = new SettingsTable(s); + graphics = new SettingsTable(s); + sound = new SettingsTable(s); - menu.defaults().size(300f, 60f).pad(3f); - menu.addButton("$text.settings.game", () -> visible(0)); - menu.row(); - menu.addButton("$text.settings.graphics", () -> visible(1)); - menu.row(); - menu.addButton("$text.settings.sound", () -> visible(2)); - if(!Vars.mobile) { - menu.row(); - menu.addButton("$text.settings.controls", ui.controls::show); - } - menu.row(); - menu.addButton("$text.settings.language", ui.language::show); + prefs = new Table(); + prefs.top(); + prefs.margin(14f); - prefs.clearChildren(); - prefs.add(menu); + menu.defaults().size(300f, 60f).pad(3f); + menu.addButton("$text.settings.game", () -> visible(0)); + menu.row(); + menu.addButton("$text.settings.graphics", () -> visible(1)); + menu.row(); + menu.addButton("$text.settings.sound", () -> visible(2)); + if(!Vars.mobile){ + menu.row(); + menu.addButton("$text.settings.controls", ui.controls::show); + } + menu.row(); + menu.addButton("$text.settings.language", ui.language::show); - ScrollPane pane = new ScrollPane(prefs, "clear"); - pane.addCaptureListener(new InputListener() { - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { - Element actor = pane.hit(x, y, true); - if (actor instanceof Slider) { - pane.setFlickScroll(false); - return true; - } + prefs.clearChildren(); + prefs.add(menu); - return super.touchDown(event, x, y, pointer, button); - } + ScrollPane pane = new ScrollPane(prefs, "clear"); + pane.addCaptureListener(new InputListener(){ + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){ + Element actor = pane.hit(x, y, true); + if(actor instanceof Slider){ + pane.setFlickScroll(false); + return true; + } - @Override - public void touchUp(InputEvent event, float x, float y, int pointer, int button) { - pane.setFlickScroll(true); - super.touchUp(event, x, y, pointer, button); - } - }); - pane.setFadeScrollBars(false); + return super.touchDown(event, x, y, pointer, button); + } - row(); - add(pane).grow().top(); - row(); - add(buttons()).fillX(); + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, int button){ + pane.setFlickScroll(true); + super.touchUp(event, x, y, pointer, button); + } + }); + pane.setFadeScrollBars(false); - hidden(this::back); + row(); + add(pane).grow().top(); + row(); + add(buttons()).fillX(); - addSettings(); - } + hidden(this::back); - void addSettings(){ - sound.volumePrefs(); + addSettings(); + } - game.screenshakePref(); - //game.checkPref("smoothcam", true); - game.checkPref("effects", true); - //game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%"); - game.sliderPref("saveinterval", 90, 10, 5*120, i -> Bundles.format("setting.seconds", i)); + void addSettings(){ + sound.volumePrefs(); - if(!gwt){ - graphics.checkPref("multithread", true, threads::setEnabled); + game.screenshakePref(); + //game.checkPref("smoothcam", true); + game.checkPref("effects", true); + //game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%"); + game.sliderPref("saveinterval", 90, 10, 5 * 120, i -> Bundles.format("setting.seconds", i)); - if(Settings.getBool("multithread")){ - threads.setEnabled(true); - } - } + if(!gwt){ + graphics.checkPref("multithread", true, threads::setEnabled); - if(!mobile && !gwt) { - graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b)); - graphics.checkPref("fullscreen", false, b -> { - if (b) { - Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); - } else { - Gdx.graphics.setWindowedMode(600, 480); - } - }); + if(Settings.getBool("multithread")){ + threads.setEnabled(true); + } + } - Gdx.graphics.setVSync(Settings.getBool("vsync")); - if(Settings.getBool("fullscreen")){ - Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); - } - } + if(!mobile && !gwt){ + graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b)); + graphics.checkPref("fullscreen", false, b -> { + if(b){ + Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); + }else{ + Gdx.graphics.setWindowedMode(600, 480); + } + }); - graphics.checkPref("fps", false); - graphics.checkPref("lasers", true); - graphics.checkPref("healthbars", true); - graphics.checkPref("minimap", !mobile); //minimap is disabled by default on mobile devices - } + Gdx.graphics.setVSync(Settings.getBool("vsync")); + if(Settings.getBool("fullscreen")){ + Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); + } + } - private void back(){ - prefs.clearChildren(); - prefs.add(menu); - } + graphics.checkPref("fps", false); + graphics.checkPref("lasers", true); + graphics.checkPref("healthbars", true); + graphics.checkPref("minimap", !mobile); //minimap is disabled by default on mobile devices + } - private void visible(int index){ - prefs.clearChildren(); - Table table = Mathf.select(index, game, graphics, sound); + private void back(){ + prefs.clearChildren(); + prefs.add(menu); + } + + private void visible(int index){ + prefs.clearChildren(); + Table table = Mathf.select(index, game, graphics, sound); prefs.add(table); - } - - @Override - public void addCloseButton(){ - buttons().addImageTextButton("$text.menu", "icon-arrow-left", 30f, this::hide).size(230f, 64f); - - keyDown(key->{ - if(key == Keys.ESCAPE || key == Keys.BACK) - hide(); - }); - } + } + + @Override + public void addCloseButton(){ + buttons().addImageTextButton("$text.menu", "icon-arrow-left", 30f, this::hide).size(230f, 64f); + + keyDown(key -> { + if(key == Keys.ESCAPE || key == Keys.BACK) + hide(); + }); + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java index 1874ec157c..39eece4f47 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java @@ -5,7 +5,7 @@ import io.anuke.mindustry.net.TraceInfo; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Bundles; -public class TraceDialog extends FloatingDialog { +public class TraceDialog extends FloatingDialog{ public TraceDialog(){ super("$text.trace"); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/UnlocksDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/UnlocksDialog.java index ce2de1999d..7bc8d5e445 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/UnlocksDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/UnlocksDialog.java @@ -15,9 +15,9 @@ import io.anuke.ucore.scene.utils.UIUtils; import static io.anuke.mindustry.Vars.control; -public class UnlocksDialog extends FloatingDialog { +public class UnlocksDialog extends FloatingDialog{ - public UnlocksDialog() { + public UnlocksDialog(){ super("$text.unlocks"); addCloseButton(); @@ -38,27 +38,27 @@ public class UnlocksDialog extends FloatingDialog { Array array = allContent.get(key); if(array.size == 0 || !(array.first() instanceof UnlockableContent)) continue; - table.add("$content." +key + ".name").growX().left().color(Palette.accent); + table.add("$content." + key + ".name").growX().left().color(Palette.accent); table.row(); table.addImage("white").growX().pad(5).padLeft(0).padRight(0).height(3).color(Palette.accent); table.row(); table.table(list -> { list.left(); - int maxWidth = UIUtils.portrait() ? 7 : 14; - int size = 8*6; + int maxWidth = UIUtils.portrait() ? 7 : 13; + int size = 8 * 6; int count = 0; - for (int i = 0; i < array.size; i++) { - UnlockableContent unlock = (UnlockableContent)array.get(i); + for(int i = 0; i < array.size; i++){ + UnlockableContent unlock = (UnlockableContent) array.get(i); if(unlock.isHidden()) continue; Image image = control.database().isUnlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-locked"); list.add(image).size(size).pad(3); - if(control.database().isUnlocked(unlock)) { + if(control.database().isUnlocked(unlock)){ image.clicked(() -> Vars.ui.content.show(unlock)); image.addListener(new Tooltip<>(new Table("clear"){{ add(unlock.localizedName()); diff --git a/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java index 793da24841..55c96f856b 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java @@ -10,29 +10,29 @@ import io.anuke.ucore.scene.ui.layout.Unit; import static io.anuke.mindustry.Vars.state; -public class BackgroundFragment extends Fragment { +public class BackgroundFragment extends Fragment{ @Override - public void build(Group parent) { + public void build(Group parent){ Core.scene.table().addRect((a, b, w, h) -> { Draw.color(); TextureRegion back = Draw.region("background"); - float backscl = (int)Math.max(Gdx.graphics.getWidth() / (float)back.getRegionWidth() * 1.5f, Unit.dp.scl(5f)); + float backscl = (int) Math.max(Gdx.graphics.getWidth() / (float) back.getRegionWidth() * 1.5f, Unit.dp.scl(5f)); Draw.alpha(0.5f); - Core.batch.draw(back, w/2 - back.getRegionWidth()*backscl/2, h/2 - back.getRegionHeight()*backscl/2, - back.getRegionWidth()*backscl, back.getRegionHeight()*backscl); + Core.batch.draw(back, w / 2 - back.getRegionWidth() * backscl / 2, h / 2 - back.getRegionHeight() * backscl / 2, + back.getRegionWidth() * backscl, back.getRegionHeight() * backscl); boolean portrait = Gdx.graphics.getWidth() < Gdx.graphics.getHeight(); - float logoscl = (int)Unit.dp.scl(7) * (portrait ? 5f/7f : 1f); + float logoscl = (int) Unit.dp.scl(7) * (portrait ? 5f / 7f : 1f); TextureRegion logo = Core.skin.getRegion("logotext"); - float logow = logo.getRegionWidth()*logoscl; - float logoh = logo.getRegionHeight()*logoscl; + float logow = logo.getRegionWidth() * logoscl; + float logoh = logo.getRegionHeight() * logoscl; Draw.color(); - Core.batch.draw(logo, (int)(w/2 - logow/2), (int)(h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0)), logow, logoh); + Core.batch.draw(logo, (int) (w / 2 - logow / 2), (int) (h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0)), logow, logoh); }).visible(() -> state.is(State.menu)).grow(); } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java index 2ad8787086..b122811e16 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java @@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.Align; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.input.InputHandler; +import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Graphics; @@ -18,17 +19,18 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.tilesize; -public class BlockConfigFragment extends Fragment { +public class BlockConfigFragment extends Fragment{ private Table table = new Table(); private InputHandler input; private Tile configTile; + private Block configBlock; public BlockConfigFragment(InputHandler input){ this.input = input; } @Override - public void build(Group parent) { + public void build(Group parent){ parent.addChild(table); } @@ -42,6 +44,7 @@ public class BlockConfigFragment extends Fragment { public void showConfig(Tile tile){ configTile = tile; + configBlock = tile.block(); table.setVisible(true); table.clear(); @@ -63,9 +66,9 @@ public class BlockConfigFragment extends Fragment { } table.setOrigin(Align.center); - Vector2 pos = Graphics.screen(tile.drawx(), tile.drawy() - tile.block().size * tilesize/2f - 1); + Vector2 pos = Graphics.screen(tile.drawx(), tile.drawy() - tile.block().size * tilesize / 2f - 1); table.setPosition(pos.x, pos.y, Align.top); - if(configTile == null || configTile.block() == Blocks.air){ + if(configTile == null || configTile.block() == Blocks.air || configTile.block() != configBlock){ hideConfig(); } }); diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockConsumeFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockConsumeFragment.java new file mode 100644 index 0000000000..eed5e343aa --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockConsumeFragment.java @@ -0,0 +1,115 @@ +package io.anuke.mindustry.ui.fragments; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.ObjectSet; +import io.anuke.mindustry.core.GameState.State; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.graphics.Palette; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.consumers.Consume; +import io.anuke.ucore.core.Graphics; +import io.anuke.ucore.scene.Group; +import io.anuke.ucore.scene.ui.layout.Table; + +import static io.anuke.mindustry.Vars.*; + +public class BlockConsumeFragment extends Fragment{ + private Table table; + private boolean visible; + + @Override + public void build(Group parent){ + table = new Table(); + table.setVisible(() -> !state.is(State.menu) && visible); + table.setTransform(true); + parent.setTransform(true); + parent.addChild(table); + } + + public void show(Tile tile){ + ObjectSet consumers = new ObjectSet<>(); + TileEntity entity = tile.entity; + Block block = tile.block(); + Consume[] lastCurrent = {null}; + + table.clearChildren(); + + //table.background("clear"); + rebuild(block, entity); + visible = true; + + table.update(() -> { + + if(tile.entity == null){ + hide(); + return; + } + + boolean rebuild = false; + + for(Consume c : block.consumes.array()){ + boolean valid = c.isOptional() || c.valid(block, entity); + + if(consumers.contains(c) == valid){ + if(valid){ + consumers.remove(c); + }else{ + consumers.add(c); + } + rebuild = true; + } + } + + if(rebuild){ + rebuild(block, entity); + } + + Vector2 v = Graphics.screen(tile.drawx() - tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f); + table.pack(); + table.setPosition(v.x, v.y, Align.topRight); + }); + + table.act(Gdx.graphics.getDeltaTime()); + } + + public void hide(){ + table.clear(); + table.update(() -> { + }); + visible = false; + } + + private void rebuild(Block block, TileEntity entity){ + table.clearChildren(); + table.left(); + + int scale = mobile ? 4 : 3; + + for(Consume c : block.consumes.array()){ + if(!c.isOptional() && !c.valid(block, entity)){ + boolean[] hovered = {false}; + + table.table("inventory", c::buildTooltip).visible(() -> hovered[0]).height(scale * 10 + 6).padBottom(-4).right().update(t -> { + if(t.getChildren().size == 0) t.remove(); + }).get().act(0); + + Table result = table.table(out -> { + out.addImage(c.getIcon()).size(10 * scale).color(Color.DARK_GRAY).padRight(-10 * scale).padBottom(-scale * 2); + out.addImage(c.getIcon()).size(10 * scale).color(Palette.accent); + out.addImage("icon-missing").size(10 * scale).color(Palette.remove).padLeft(-10 * scale); + }).size(10 * scale).get(); + + result.hovered(() -> hovered[0] = true); + if(!mobile){ + result.exited(() -> hovered[0] = false); + } + + table.row(); + } + } + } +} diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java index 4ac97e9f02..bfc30db2df 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java @@ -16,7 +16,6 @@ import io.anuke.mindustry.type.Item; import io.anuke.mindustry.ui.ItemImage; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.Graphics; -import io.anuke.ucore.core.Inputs; import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.BooleanProvider; import io.anuke.ucore.scene.Group; @@ -29,11 +28,9 @@ import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Strings; -import static io.anuke.mindustry.Vars.mobile; -import static io.anuke.mindustry.Vars.state; -import static io.anuke.mindustry.Vars.tilesize; +import static io.anuke.mindustry.Vars.*; -public class BlockInventoryFragment extends Fragment { +public class BlockInventoryFragment extends Fragment{ private final static float holdWithdraw = 40f; private Table table; @@ -47,8 +44,20 @@ public class BlockInventoryFragment extends Fragment { this.input = input; } + @Remote(called = Loc.server, targets = Loc.both, in = In.blocks, forward = true) + public static void requestItem(Player player, Tile tile, Item item, int amount){ + if(player == null) return; + + int removed = tile.block().removeStack(tile, item, amount); + + player.inventory.addItem(item, removed); + for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ + Timers.run(j * 3f, () -> CallEntity.transferItemEffect(item, tile.drawx(), tile.drawy(), player)); + } + } + @Override - public void build(Group parent) { + public void build(Group parent){ table = new Table(); table.setVisible(() -> !state.is(State.menu)); table.setTransform(true); @@ -58,8 +67,9 @@ public class BlockInventoryFragment extends Fragment { public void showFor(Tile t){ this.tile = t.target(); - if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.totalItems() == 0) return; - rebuild(); + if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0) + return; + rebuild(true); } public void hide(){ @@ -71,23 +81,24 @@ public class BlockInventoryFragment extends Fragment { tile = null; } - private void rebuild(){ + private void rebuild(boolean actions){ + Player player = input.player; IntSet container = new IntSet(); - table.clear(); + table.clearChildren(); table.background("inventory"); table.setTouchable(Touchable.enabled); table.update(() -> { - if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.totalItems() == 0){ + if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0){ hide(); }else{ if(holding && lastItem != null){ holdTime += Timers.delta(); if(holdTime >= holdWithdraw){ - int amount = Math.min(tile.entity.items.getItem(lastItem), player.inventory.itemCapacityUsed(lastItem)); + int amount = Math.min(tile.entity.items.get(lastItem), player.inventory.itemCapacityUsed(lastItem)); CallBlocks.requestItem(player, tile, lastItem, amount); holding = false; holdTime = 0f; @@ -95,11 +106,11 @@ public class BlockInventoryFragment extends Fragment { } updateTablePosition(); - if(tile.block().hasItems) { - int[] items = tile.entity.items.items; - for (int i = 0; i < items.length; i++) { - if ((items[i] == 0) == container.contains(i)) { - rebuild(); + if(tile.block().hasItems){ + for(int i = 0; i < Item.all().size; i++){ + boolean has = tile.entity.items.has(Item.getByID(i)); + if(has != container.contains(i)){ + rebuild(false); } } } @@ -110,15 +121,13 @@ public class BlockInventoryFragment extends Fragment { int row = 0; table.margin(6f); - table.defaults().size(mobile ? 16*3 : 16*2).space(6f); + table.defaults().size(mobile ? 16 * 3 : 16 * 2).space(6f); - if(tile.block().hasItems) { - int[] items = tile.entity.items.items; + if(tile.block().hasItems){ - for (int i = 0; i < items.length; i++) { - final int f = i; - if (items[i] == 0) continue; + for(int i = 0; i < Item.all().size; i++){ Item item = Item.getByID(i); + if(!tile.entity.items.has(item)) continue; container.add(i); @@ -127,14 +136,19 @@ public class BlockInventoryFragment extends Fragment { HandCursorListener l = new HandCursorListener(); l.setEnabled(canPick); - ItemImage image = new ItemImage(item.region, () -> round(items[f])); + ItemImage image = new ItemImage(item.region, () -> { + if(tile == null || tile.entity == null){ + return ""; + } + return round(tile.entity.items.get(item)); + }); image.addListener(l); image.addListener(new InputListener(){ @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { - if(!canPick.get() || items[f] == 0) return false; - int amount = Math.min(Inputs.keyDown("item_withdraw") ? items[f] : 1, player.inventory.itemCapacityUsed(item)); + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){ + if(!canPick.get() || !tile.entity.items.has(item)) return false; + int amount = Math.min(1, player.inventory.itemCapacityUsed(item)); CallBlocks.requestItem(player, tile, item, amount); lastItem = item; holding = true; @@ -143,14 +157,14 @@ public class BlockInventoryFragment extends Fragment { } @Override - public void touchUp(InputEvent event, float x, float y, int pointer, int button) { + public void touchUp(InputEvent event, float x, float y, int pointer, int button){ holding = false; lastItem = null; } }); table.add(image); - if (row++ % cols == cols - 1) table.row(); + if(row++ % cols == cols - 1) table.row(); } } @@ -160,34 +174,24 @@ public class BlockInventoryFragment extends Fragment { updateTablePosition(); - table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), - Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out)); + if(actions){ + table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), + Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out)); + } } private String round(float f){ - f = (int)f; + f = (int) f; if(f >= 1000){ - return Strings.toFixed(f/1000, 1) + "k"; + return Strings.toFixed(f / 1000, 1) + "k"; }else{ - return (int)f+""; + return (int) f + ""; } } private void updateTablePosition(){ - Vector2 v = Graphics.screen(tile.drawx() + tile.block().size * tilesize/2f, tile.drawy() + tile.block().size * tilesize/2f); + Vector2 v = Graphics.screen(tile.drawx() + tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f); table.pack(); table.setPosition(v.x, v.y, Align.topLeft); } - - @Remote(called = Loc.server, targets = Loc.both, in = In.blocks, forward = true) - public static void requestItem(Player player, Tile tile, Item item, int amount){ - if(player == null) return; - - int removed = tile.block().removeStack(tile, item, amount); - - player.inventory.addItem(item, removed); - for(int j = 0; j < Mathf.clamp(removed/3, 1, 8); j ++){ - Timers.run(j*3f, () -> CallEntity.transferItemEffect(item, tile.drawx(), tile.drawy(), player)); - } - } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java index ddff5a96ce..a6949bcdf6 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java @@ -29,327 +29,344 @@ import io.anuke.ucore.util.Strings; import static io.anuke.mindustry.Vars.*; public class BlocksFragment extends Fragment{ - /**Table containing description that is shown on top.*/ - private Table descTable; - /**Main table containing the whole menu.*/ - private Table mainTable; - /**Table for all section buttons and blocks.*/ - private Table selectTable; - /**Whether the whole thing is shown or hidden by the popup button.*/ - private boolean shown = true; - /**Recipe currently hovering over.*/ - private Recipe hoverRecipe; - /**Last category selected.*/ - private Category lastCategory; - /**Last block pane scroll Y position.*/ - private float lastScroll; - /**Temporary recipe array for storage*/ - private Array recipes = new Array<>(); - - //number of block icon rows - private static final int rows = 4; - //number of category button rows - private static final int secrows = 4; - //size of each block icon - private static final float size = 48; - //maximum recipe rows - private static final int maxrow = 3; - - public void build(Group parent){ - InputHandler input = control.input(0); - - //create container table - new table(){{ - abottom(); - aright(); - - //make it only be shown when needed. - visible(() -> !state.is(State.menu)); - - //create the main blocks table - mainTable = new table(){{ - - //add top description table - descTable = new Table("button"); - descTable.setVisible(() -> hoverRecipe != null || input.recipe != null); //make sure it's visible when necessary - descTable.update(() -> { - // note: This is required because there is no direct connection between - // input.recipe and the description ui. If input.recipe gets set to null - // a proper cleanup of the ui elements is required. - boolean anyRecipeShown = input.recipe != null || hoverRecipe != null; - boolean descriptionTableClean = descTable.getChildren().size == 0; - boolean cleanupRequired = !anyRecipeShown && !descriptionTableClean; - if(cleanupRequired){ - descTable.clear(); - } - }); - - add(descTable).fillX().uniformX(); - - row(); - - //now add the block selection menu - selectTable = new table("pane") {{ - touchable(Touchable.enabled); - - margin(10f); - marginLeft(0f); - marginRight(0f); - marginTop(-5); - - }}.right().bottom().end().get(); - - visible(() -> !state.is(State.menu)); - - }}.end().get(); - - }}.end(); - - rebuild(); - } - - /**Rebuilds the whole placement menu, attempting to preserve previous state.*/ - void rebuild(){ - selectTable.clear(); - - InputHandler input = control.input(0); - Stack stack = new Stack(); - ButtonGroup group = new ButtonGroup<>(); - Table catTable = selectTable; - - int cati = 0; - int checkedi = 0; - int rowsUsed = 0; - - //add categories - for (Category cat : Category.values()) { - //get recipes out by category - Recipe.getUnlockedByCategory(cat, recipes); - - //empty section, nothing to see here - if(recipes.size == 0){ - continue; - } - - //table where actual recipes go - Table recipeTable = new Table(); - recipeTable.margin(4).top().left().marginRight(15); - - //add a new row here when needed - if (cati == secrows) { - catTable = new Table(); - selectTable.row(); - selectTable.add(catTable).colspan(secrows).padTop(-5).growX(); - } - - //add category button - ImageButton catb = catTable.addImageButton( "icon-" + cat.name(), "toggle", 40, () -> { - if (!recipeTable.isVisible() && input.recipe != null) { - input.recipe = null; - } - lastCategory = cat; - stack.act(Gdx.graphics.getDeltaTime()); - stack.act(Gdx.graphics.getDeltaTime()); - }).growX().height(54).group(group) - .name("sectionbutton" + cat.name()).get(); - - if(lastCategory == cat || lastCategory == null){ - checkedi = cati; - lastCategory = cat; - } - - //scrollpane for recipes - ScrollPane pane = new ScrollPane(recipeTable, "clear-black"); - pane.setOverscroll(false, false); - pane.setVisible(catb::isChecked); - pane.setScrollYForce(lastScroll); - pane.update(() -> { - Element e = Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true); - if(e != null && e.isDescendantOf(pane)){ - Core.scene.setScrollFocus(pane); - }else if(Core.scene.getScrollFocus() == pane){ - Core.scene.setScrollFocus(null); - } - - if(lastCategory == cat){ - lastScroll = pane.getVisualScrollY(); - } - }); - stack.add(pane); - - int i = 0; - - //add actual recipes - for (Recipe r : recipes) { - if((r.debugOnly && !debug) || (r.desktopOnly && mobile)) continue; - - ImageButton image = new ImageButton(new TextureRegion(), "select"); - - TextureRegion[] regions = r.result.getCompactIcon(); - Stack istack = new Stack(); - for(TextureRegion region : regions){ - Image u = new Image(region); - u.update(() -> u.setColor(istack.getColor())); - istack.add(u); - } - - image.getImageCell().setActor(istack).size(size); - image.addChild(istack); - image.setTouchable(Touchable.enabled); - image.getImage().remove(); - - image.addListener(new ClickListener(){ - @Override - public void enter(InputEvent event, float x, float y, int pointer, Element fromActor) { - super.enter(event, x, y, pointer, fromActor); - if (hoverRecipe != r) { - hoverRecipe = r; - updateRecipe(r); - } - } - - @Override - public void exit(InputEvent event, float x, float y, int pointer, Element toActor) { - super.exit(event, x, y, pointer, toActor); - hoverRecipe = null; - updateRecipe(input.recipe); - } - }); - - image.clicked(() -> { - // note: input.recipe only gets set here during a click. - // during a hover only the visual description will be updated. - InputHandler handler = mobile ? input : control.input(0); - - boolean nothingSelectedYet = handler.recipe == null; - boolean selectedSomethingElse = !nothingSelectedYet && handler.recipe != r; - boolean shouldMakeSelection = nothingSelectedYet || selectedSomethingElse; - if (shouldMakeSelection) { - handler.recipe = r; - hoverRecipe = r; - updateRecipe(r); - } else { - handler.recipe = null; - hoverRecipe = null; - updateRecipe(null); - } - }); - - recipeTable.add(image).size(size + 8); - - image.update(() -> { - image.setChecked(r == control.input(0).recipe); - TileEntity entity = players[0].getClosestCore(); - - if(entity == null) return; - - for(ItemStack s : r.requirements){ - if(!entity.items.hasItem(s.item, Mathf.ceil(s.amount))){ - istack.setColor(Color.GRAY); - return; - } - } - istack.setColor(Color.WHITE); - }); - - if (i % rows == rows - 1) { - rowsUsed = Math.max((i+1)/rows, rowsUsed); - recipeTable.row(); - } - - i++; - } - - cati ++; - } - - if(group.getButtons().size > 0){ - group.getButtons().get(checkedi).setChecked(true); - } - - selectTable.row(); - selectTable.add(stack).growX().left().top().colspan(Category.values().length).padBottom(-5).height((size + 12)*rowsUsed); - } - - void toggle(boolean show, float t, Interpolation ip){ - if(shown){ - shown = false; - mainTable.actions(Actions.translateBy(0, mainTable.getTranslation().y + (-mainTable.getHeight() - descTable.getHeight()), t, ip)); - }else{ - shown = true; - mainTable.actions(Actions.translateBy(0, -mainTable.getTranslation().y, t, ip)); - } - } - - private void updateRecipe(Recipe recipe){ - if (recipe == null) { - descTable.clear(); - return; - } - - descTable.clear(); - descTable.setTouchable(Touchable.enabled); - - descTable.defaults().left(); - descTable.left(); - descTable.margin(12); - - Table header = new Table(); - - descTable.add(header).left(); - - descTable.row(); - - TextureRegion[] regions = recipe.result.getCompactIcon(); - - Stack istack = new Stack(); - - for(TextureRegion region : regions) istack.add(new Image(region)); - - header.add(istack).size(8*5).padTop(4); - Label nameLabel = new Label(recipe.result.formalName); - nameLabel.setWrap(true); - header.add(nameLabel).padLeft(2).width(120f); - - header.addButton("?", () -> ui.content.show(recipe)).expandX().padLeft(3).top().right().size(40f, 44f).padTop(-2); - - descTable.add().pad(2); - - Table requirements = new Table(); - - descTable.row(); - - descTable.add(requirements); - descTable.left(); - - for(ItemStack stack : recipe.requirements){ - requirements.addImage(stack.item.region).size(8*3); - Label reqlabel = new Label(() ->{ - TileEntity core = players[0].getClosestCore(); - if(core == null) return "*/*"; + //number of block icon rows + private static final int rows = 4; + //number of category button rows + private static final int secrows = 4; + //size of each block icon + private static final float size = 48; + //maximum recipe rows + private static final int maxrow = 3; + /** + * Table containing description that is shown on top. + */ + private Table descTable; + /** + * Main table containing the whole menu. + */ + private Table mainTable; + /** + * Table for all section buttons and blocks. + */ + private Table selectTable; + /** + * Whether the whole thing is shown or hidden by the popup button. + */ + private boolean shown = true; + /** + * Recipe currently hovering over. + */ + private Recipe hoverRecipe; + /** + * Last category selected. + */ + private Category lastCategory; + /** + * Last block pane scroll Y position. + */ + private float lastScroll; + /** + * Temporary recipe array for storage + */ + private Array recipes = new Array<>(); + + public void build(Group parent){ + InputHandler input = control.input(0); + + //create container table + new table(){{ + abottom(); + aright(); + + //make it only be shown when needed. + visible(() -> !state.is(State.menu)); + + //create the main blocks table + mainTable = new table(){{ + + //add top description table + descTable = new Table("button"); + descTable.setVisible(() -> hoverRecipe != null || input.recipe != null); //make sure it's visible when necessary + descTable.update(() -> { + // note: This is required because there is no direct connection between + // input.recipe and the description ui. If input.recipe gets set to null + // a proper cleanup of the ui elements is required. + boolean anyRecipeShown = input.recipe != null || hoverRecipe != null; + boolean descriptionTableClean = descTable.getChildren().size == 0; + boolean cleanupRequired = !anyRecipeShown && !descriptionTableClean; + if(cleanupRequired){ + descTable.clear(); + } + }); + + add(descTable).fillX().uniformX(); + + row(); + + //now add the block selection menu + selectTable = new table("pane"){{ + touchable(Touchable.enabled); + + margin(10f); + marginLeft(0f); + marginRight(0f); + marginTop(-5); + + }}.right().bottom().end().get(); + + visible(() -> !state.is(State.menu)); + + }}.end().get(); + + }}.end(); + + rebuild(); + } + + /** + * Rebuilds the whole placement menu, attempting to preserve previous state. + */ + void rebuild(){ + selectTable.clear(); + + InputHandler input = control.input(0); + Stack stack = new Stack(); + ButtonGroup group = new ButtonGroup<>(); + Table catTable = selectTable; + + int cati = 0; + int checkedi = 0; + int rowsUsed = 0; + + //add categories + for(Category cat : Category.values()){ + //get recipes out by category + Recipe.getUnlockedByCategory(cat, recipes); + + //empty section, nothing to see here + if(recipes.size == 0){ + continue; + } + + //table where actual recipes go + Table recipeTable = new Table(); + recipeTable.margin(4).top().left().marginRight(15); + + //add a new row here when needed + if(cati == secrows){ + catTable = new Table(); + selectTable.row(); + selectTable.add(catTable).colspan(secrows).padTop(-5).growX(); + } + + //add category button + ImageButton catb = catTable.addImageButton("icon-" + cat.name(), "toggle", 40, () -> { + if(!recipeTable.isVisible() && input.recipe != null){ + input.recipe = null; + } + lastCategory = cat; + stack.act(Gdx.graphics.getDeltaTime()); + stack.act(Gdx.graphics.getDeltaTime()); + }).growX().height(54).group(group) + .name("sectionbutton" + cat.name()).get(); + + if(lastCategory == cat || lastCategory == null){ + checkedi = cati; + lastCategory = cat; + } + + //scrollpane for recipes + ScrollPane pane = new ScrollPane(recipeTable, "clear-black"); + pane.setOverscroll(false, false); + pane.setVisible(catb::isChecked); + pane.setScrollYForce(lastScroll); + pane.update(() -> { + Element e = Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true); + if(e != null && e.isDescendantOf(pane)){ + Core.scene.setScrollFocus(pane); + }else if(Core.scene.getScrollFocus() == pane){ + Core.scene.setScrollFocus(null); + } + + if(lastCategory == cat){ + lastScroll = pane.getVisualScrollY(); + } + }); + stack.add(pane); + + int i = 0; + + //add actual recipes + for(Recipe r : recipes){ + if((r.debugOnly && !debug) || (r.desktopOnly && mobile)) continue; + + ImageButton image = new ImageButton(new TextureRegion(), "select"); + + TextureRegion[] regions = r.result.getCompactIcon(); + Stack istack = new Stack(); + for(TextureRegion region : regions){ + Image u = new Image(region); + u.update(() -> u.setColor(istack.getColor())); + istack.add(u); + } + + image.getImageCell().setActor(istack).size(size); + image.addChild(istack); + image.setTouchable(Touchable.enabled); + image.getImage().remove(); + + image.addListener(new ClickListener(){ + @Override + public void enter(InputEvent event, float x, float y, int pointer, Element fromActor){ + super.enter(event, x, y, pointer, fromActor); + if(hoverRecipe != r){ + hoverRecipe = r; + updateRecipe(r); + } + } + + @Override + public void exit(InputEvent event, float x, float y, int pointer, Element toActor){ + super.exit(event, x, y, pointer, toActor); + hoverRecipe = null; + updateRecipe(input.recipe); + } + }); + + image.clicked(() -> { + // note: input.recipe only gets set here during a click. + // during a hover only the visual description will be updated. + InputHandler handler = mobile ? input : control.input(0); + + boolean nothingSelectedYet = handler.recipe == null; + boolean selectedSomethingElse = !nothingSelectedYet && handler.recipe != r; + boolean shouldMakeSelection = nothingSelectedYet || selectedSomethingElse; + if(shouldMakeSelection){ + handler.recipe = r; + hoverRecipe = r; + updateRecipe(r); + }else{ + handler.recipe = null; + hoverRecipe = null; + updateRecipe(null); + } + }); + + recipeTable.add(image).size(size + 8); + + image.update(() -> { + image.setChecked(r == control.input(0).recipe); + TileEntity entity = players[0].getClosestCore(); + + if(entity == null) return; + + for(ItemStack s : r.requirements){ + if(!entity.items.has(s.item, Mathf.ceil(s.amount))){ + istack.setColor(Color.GRAY); + return; + } + } + istack.setColor(Color.WHITE); + }); + + if(i % rows == rows - 1){ + rowsUsed = Math.max((i + 1) / rows, rowsUsed); + recipeTable.row(); + } + + i++; + } + + cati++; + } + + if(group.getButtons().size > 0){ + group.getButtons().get(checkedi).setChecked(true); + } + + selectTable.row(); + selectTable.add(stack).growX().left().top().colspan(Category.values().length).padBottom(-5).height((size + 12) * rowsUsed); + } + + void toggle(boolean show, float t, Interpolation ip){ + if(shown){ + shown = false; + mainTable.actions(Actions.translateBy(0, mainTable.getTranslation().y + (-mainTable.getHeight() - descTable.getHeight()), t, ip)); + }else{ + shown = true; + mainTable.actions(Actions.translateBy(0, -mainTable.getTranslation().y, t, ip)); + } + } + + private void updateRecipe(Recipe recipe){ + if(recipe == null){ + descTable.clear(); + return; + } + + descTable.clear(); + descTable.setTouchable(Touchable.enabled); + + descTable.defaults().left(); + descTable.left(); + descTable.margin(12); + + Table header = new Table(); + + descTable.add(header).left(); + + descTable.row(); + + TextureRegion[] regions = recipe.result.getCompactIcon(); + + Stack istack = new Stack(); + + for(TextureRegion region : regions) istack.add(new Image(region)); + + header.add(istack).size(8 * 5).padTop(4); + Label nameLabel = new Label(recipe.result.formalName); + nameLabel.setWrap(true); + header.add(nameLabel).padLeft(2).width(120f); + + header.addButton("?", () -> ui.content.show(recipe)).expandX().padLeft(3).top().right().size(40f, 44f).padTop(-2); + + descTable.add().pad(2); + + Table requirements = new Table(); + + descTable.row(); + + descTable.add(requirements); + descTable.left(); + + for(ItemStack stack : recipe.requirements){ + requirements.addImage(stack.item.region).size(8 * 3); + Label reqlabel = new Label(() -> { + TileEntity core = players[0].getClosestCore(); + if(core == null) return "*/*"; - int amount = core.items.getItem(stack.item); - String color = (amount < stack.amount/2f ? "[red]" : amount < stack.amount ? "[orange]" : "[white]"); + int amount = core.items.get(stack.item); + String color = (amount < stack.amount / 2f ? "[red]" : amount < stack.amount ? "[orange]" : "[white]"); - return color + format(amount) + "[white]/" + stack.amount; - }); + return color + format(amount) + "[white]/" + stack.amount; + }); - requirements.add(reqlabel).left(); - requirements.row(); - } + requirements.add(reqlabel).left(); + requirements.row(); + } - descTable.row(); - } + descTable.row(); + } - String format(int number){ - if(number >= 1000000) { - return Strings.toFixed(number/1000000f, 1) + "[gray]mil[]"; - }else if(number >= 10000){ - return number/1000 + "[gray]k[]"; - }else if(number >= 1000){ - return Strings.toFixed(number/1000f, 1) + "[gray]k[]"; - }else{ - return number + ""; - } - } + String format(int number){ + if(number >= 1000000){ + return Strings.toFixed(number / 1000000f, 1) + "[gray]mil[]"; + }else if(number >= 10000){ + return number / 1000 + "[gray]k[]"; + }else if(number >= 1000){ + return Strings.toFixed(number / 1000f, 1) + "[gray]k[]"; + }else{ + return number + ""; + } + } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java index 153ed15ea5..82d67556ed 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java @@ -43,9 +43,9 @@ public class ChatFragment extends Table{ private Array history = new Array<>(); private int historyPos = 0; private int scrollPos = 0; - private Fragment container = new Fragment() { + private Fragment container = new Fragment(){ @Override - public void build(Group parent) { + public void build(Group parent){ scene.add(ChatFragment.this); } }; @@ -67,17 +67,17 @@ public class ChatFragment extends Table{ toggle(); } - if (chatOpen) { - if (Inputs.keyTap("chat_history_prev") && historyPos < history.size - 1) { - if (historyPos == 0) history.set(0, chatfield.getText()); + if(chatOpen){ + if(Inputs.keyTap("chat_history_prev") && historyPos < history.size - 1){ + if(historyPos == 0) history.set(0, chatfield.getText()); historyPos++; updateChat(); } - if (Inputs.keyTap("chat_history_next") && historyPos > 0) { + if(Inputs.keyTap("chat_history_next") && historyPos > 0){ historyPos--; updateChat(); } - scrollPos = (int)Mathf.clamp(scrollPos + Inputs.getAxis("chat_scroll"), 0, Math.max(0, messages.size - messagesShown)); + scrollPos = (int) Mathf.clamp(scrollPos + Inputs.getAxis("chat_scroll"), 0, Math.max(0, messages.size - messagesShown)); } }); @@ -85,7 +85,7 @@ public class ChatFragment extends Table{ setup(); } - public Fragment container() { + public Fragment container(){ return container; } @@ -108,16 +108,16 @@ public class ChatFragment extends Table{ chatfield.setStyle(chatfield.getStyle()); Platform.instance.addDialog(chatfield, Vars.maxTextLength); - bottom().left().marginBottom(offsety).marginLeft(offsetx*2).add(fieldlabel).padBottom(4f); + bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(4f); add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28); - if(Vars.mobile) { + if(Vars.mobile){ marginBottom(105f); marginRight(240f); } - if(Vars.mobile) { + if(Vars.mobile){ addImageButton("icon-arrow-right", 14 * 2, this::toggle).size(46f, 51f).visible(() -> chatOpen).pad(2f); } } @@ -128,7 +128,7 @@ public class ChatFragment extends Table{ batch.setColor(shadowColor); if(chatOpen) - batch.draw(skin.getRegion("white"), offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight()-1); + batch.draw(skin.getRegion("white"), offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1); super.draw(batch, alpha); @@ -143,18 +143,18 @@ public class ChatFragment extends Table{ for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || chatOpen); i++){ layout.setText(font, messages.get(i).formattedMessage, Color.WHITE, textWidth, Align.bottomLeft, true); - theight += layout.height+textspacing; - if(i - scrollPos == 0) theight -= textspacing+1; + theight += layout.height + textspacing; + if(i - scrollPos == 0) theight -= textspacing + 1; font.getCache().clear(); font.getCache().addText(messages.get(i).formattedMessage, fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true); - if(!chatOpen && fadetime-i < 1f && fadetime-i >= 0f){ - font.getCache().setAlphas(fadetime-i); - batch.setColor(0, 0, 0, shadowColor.a*(fadetime-i)); + if(!chatOpen && fadetime - i < 1f && fadetime - i >= 0f){ + font.getCache().setAlphas(fadetime - i); + batch.setColor(0, 0, 0, shadowColor.a * (fadetime - i)); } - batch.draw(skin.getRegion("white"), offsetx, theight-layout.height-2, textWidth + Unit.dp.scl(4f), layout.height+textspacing); + batch.draw(skin.getRegion("white"), offsetx, theight - layout.height - 2, textWidth + Unit.dp.scl(4f), layout.height + textspacing); batch.setColor(shadowColor); font.getCache().draw(batch); @@ -163,7 +163,7 @@ public class ChatFragment extends Table{ batch.setColor(Color.WHITE); if(fadetime > 0 && !chatOpen) - fadetime -= Timers.delta()/180f; + fadetime -= Timers.delta() / 180f; } private void sendMessage(){ @@ -197,12 +197,12 @@ public class ChatFragment extends Table{ clearChatInput(); } - public void updateChat() { + public void updateChat(){ chatfield.setText(history.get(historyPos)); chatfield.setCursorPosition(chatfield.getText().length()); } - public void clearChatInput() { + public void clearChatInput(){ historyPos = 0; history.set(0, ""); chatfield.setText(""); @@ -234,7 +234,7 @@ public class ChatFragment extends Table{ if(sender == null){ //no sender, this is a server message? formattedMessage = message; }else{ - formattedMessage = "[CORAL][["+sender+"[CORAL]]:[WHITE] "+message; + formattedMessage = "[CORAL][[" + sender + "[CORAL]]:[WHITE] " + message; } } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java index fde6ff3527..0ec1779737 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java @@ -27,7 +27,7 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; -public class DebugFragment extends Fragment { +public class DebugFragment extends Fragment{ private static StringBuilder log = new StringBuilder(); static{ @@ -35,7 +35,7 @@ public class DebugFragment extends Fragment { @Override public void print(String text, Object... args){ super.print(text, args); - if(log.length() < 1000) { + if(log.length() < 1000){ log.append(Log.format(text, args)); log.append("\n"); } @@ -43,107 +43,6 @@ public class DebugFragment extends Fragment { }); } - @Override - public void build(Group parent){ - - Player player = players[0]; - new table(){{ - visible(() -> debug); - - abottom().aleft(); - - new table("pane"){{ - defaults().fillX().width(100f); - - new label("Debug"); - row(); - new button("noclip", "toggle", () -> noclip = !noclip); - row(); - new button("items", () -> { - for (int i = 0; i < 10; i++) { - ItemDrop.create(Item.all().random(), 5, player.x, player.y, Mathf.random(360f)); - } - }); - row(); - new button("team", "toggle", player::toggleTeam); - row(); - new button("blocks", "toggle", () -> showBlockDebug = !showBlockDebug); - row(); - new button("fog", () -> showFog = !showFog); - row(); - new button("gameover", () ->{ - state.teams.get(Team.blue).cores.get(0).entity.health = 0; - state.teams.get(Team.blue).cores.get(0).entity.damage(1); - }); - row(); - new button("wave", () -> state.wavetime = 0f); - row(); - new button("death", () -> player.damage(99999, true)); - row(); - new button("spawn", () -> { - FloatingDialog dialog = new FloatingDialog("debug spawn"); - for(UnitType type : UnitType.all()){ - dialog.content().addImageButton("white", 40, () -> { - dialog.hide(); - BaseUnit unit = type.create(player.getTeam()); - unit.inventory.addAmmo(type.weapon.getAmmoType(type.weapon.getAcceptedItems().iterator().next())); - unit.setWave(); - unit.set(player.x, player.y); - unit.add(); - }).get().getStyle().imageUp = new TextureRegionDrawable(type.iconRegion); - } - dialog.addCloseButton(); - dialog.setFillParent(false); - dialog.show(); - }); - row(); - }}.end(); - - row(); - - }}.end(); - - - new table(){{ - visible(() -> console); - - atop().aleft(); - - new table("pane") {{ - defaults().fillX(); - - ScrollPane pane = new ScrollPane(new Label(DebugFragment::debugInfo), "clear"); - - add(pane); - row(); - new button("dump", () -> { - try{ - FileHandle file = Gdx.files.local("packet-dump.txt"); - file.writeString("--INFO--\n", false); - file.writeString(debugInfo(), true); - file.writeString("--LOG--\n\n", true); - file.writeString(log.toString(), true); - }catch (Exception e){ - ui.showError("Error dumping log."); - } - }); - }}.end(); - }}.end(); - - new table(){{ - visible(() -> console); - - atop(); - - Table table = new Table("pane"); - table.label(() -> log.toString()); - - ScrollPane pane = new ScrollPane(table, "clear"); - - get().add(pane); - }}.end(); - } - public static void printDebugInfo(){ Gdx.app.error("Minudstry Info Dump", debugInfo()); } @@ -164,9 +63,9 @@ public class DebugFragment extends Fragment { "units: " + totalUnits, "bullets: " + bulletGroup.size(), Net.client() ? - "chat.open: " + ui.chatfrag.chatOpen() + "\n" + - "chat.messages: " + ui.chatfrag.getMessagesSize() + "\n" + - "client.connecting: " + netClient.isConnecting() + "\n" : "", + "chat.open: " + ui.chatfrag.chatOpen() + "\n" + + "chat.messages: " + ui.chatfrag.getMessagesSize() + "\n" + + "client.connecting: " + netClient.isConnecting() + "\n" : "", "players: " + playerGroup.size(), "tiles: " + tileGroup.size(), "tiles.sleeping: " + TileEntity.sleepingEntities, @@ -210,10 +109,113 @@ public class DebugFragment extends Fragment { private static StringBuilder join(String... strings){ StringBuilder builder = new StringBuilder(); - for (String string : strings) { + for(String string : strings){ builder.append(string); builder.append("\n"); } return builder; } + + @Override + public void build(Group parent){ + + Player player = players[0]; + new table(){{ + visible(() -> debug); + + abottom().aleft(); + + new table("pane"){{ + defaults().fillX().width(100f); + + new label(() -> Gdx.app.getJavaHeap() / 1024 / 1024 + "MB"); + row(); + + new label("Debug"); + row(); + new button("noclip", "toggle", () -> noclip = !noclip); + row(); + new button("items", () -> { + for(int i = 0; i < 10; i++){ + ItemDrop.create(Item.all().random(), 5, player.x, player.y, Mathf.random(360f)); + } + }); + row(); + new button("team", "toggle", player::toggleTeam); + row(); + new button("blocks", "toggle", () -> showBlockDebug = !showBlockDebug); + row(); + new button("fog", () -> showFog = !showFog); + row(); + new button("gameover", () -> { + state.teams.get(Team.blue).cores.get(0).entity.health = 0; + state.teams.get(Team.blue).cores.get(0).entity.damage(1); + }); + row(); + new button("wave", () -> state.wavetime = 0f); + row(); + new button("death", () -> player.damage(99999, true)); + row(); + new button("spawn", () -> { + FloatingDialog dialog = new FloatingDialog("debug spawn"); + for(UnitType type : UnitType.all()){ + dialog.content().addImageButton("white", 40, () -> { + BaseUnit unit = type.create(player.getTeam()); + unit.inventory.addAmmo(type.weapon.getAmmoType(type.weapon.getAcceptedItems().iterator().next())); + unit.setWave(); + unit.set(player.x, player.y); + unit.add(); + }).get().getStyle().imageUp = new TextureRegionDrawable(type.iconRegion); + } + dialog.addCloseButton(); + dialog.setFillParent(false); + dialog.show(); + }); + row(); + }}.end(); + + row(); + + }}.end(); + + + new table(){{ + visible(() -> console); + + atop().aleft(); + + new table("pane"){{ + defaults().fillX(); + + ScrollPane pane = new ScrollPane(new Label(DebugFragment::debugInfo), "clear"); + + add(pane); + row(); + new button("dump", () -> { + try{ + FileHandle file = Gdx.files.local("packet-dump.txt"); + file.writeString("--INFO--\n", false); + file.writeString(debugInfo(), true); + file.writeString("--LOG--\n\n", true); + file.writeString(log.toString(), true); + }catch(Exception e){ + ui.showError("Error dumping log."); + } + }); + }}.end(); + }}.end(); + + new table(){{ + visible(() -> console); + + atop(); + + Table table = new Table("pane"); + table.label(() -> log.toString()); + + ScrollPane pane = new ScrollPane(table, "clear"); + + get().add(pane); + }}.end(); + } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/Fragment.java b/core/src/io/anuke/mindustry/ui/fragments/Fragment.java index f28b87f8dc..080c2c4a05 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/Fragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/Fragment.java @@ -3,5 +3,5 @@ package io.anuke.mindustry.ui.fragments; import io.anuke.ucore.scene.Group; public abstract class Fragment{ - public abstract void build(Group parent); + public abstract void build(Group parent); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 8fb5334a82..f0980dac14 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -34,316 +34,318 @@ import io.anuke.ucore.util.Bundles; import static io.anuke.mindustry.Vars.*; public class HudFragment extends Fragment{ - public final BlocksFragment blockfrag = new BlocksFragment(); + public final BlocksFragment blockfrag = new BlocksFragment(); - private ImageButton menu, flip; - private Table respawntable; - private Table wavetable; - private Table infolabel; - private Table lastUnlockTable; - private Table lastUnlockLayout; - private boolean shown = true; - private float dsize = 58; - private float isize = 40; + private ImageButton menu, flip; + private Table respawntable; + private Table wavetable; + private Table infolabel; + private Table lastUnlockTable; + private Table lastUnlockLayout; + private boolean shown = true; + private float dsize = 58; + private float isize = 40; - public void build(Group parent){ + public void build(Group parent){ - //menu at top left - new table(){{ - atop(); - aleft(); + //menu at top left + new table(){{ + atop(); + aleft(); - new table(){{ + new table(){{ - new table() {{ - left(); - defaults().size(dsize).left(); + new table(){{ + left(); + defaults().size(dsize).left(); - menu = new imagebutton("icon-menu", isize, ui.paused::show).get(); - flip = new imagebutton("icon-arrow-up", isize, () -> toggleMenus()).get(); + menu = new imagebutton("icon-menu", isize, ui.paused::show).get(); + flip = new imagebutton("icon-arrow-up", isize, () -> toggleMenus()).get(); - update(t -> { - if(Inputs.keyTap("toggle_menus") && !ui.chatfrag.chatOpen()){ - toggleMenus(); - } - }); + update(t -> { + if(Inputs.keyTap("toggle_menus") && !ui.chatfrag.chatOpen()){ + toggleMenus(); + } + }); - new imagebutton("icon-pause", isize, () -> { - if (Net.active()) { - ui.listfrag.toggle(); - } else { - state.set(state.is(State.paused) ? State.playing : State.paused); - } - }).update(i -> { - if (Net.active()) { - i.getStyle().imageUp = Core.skin.getDrawable("icon-players"); - } else { - i.setDisabled(Net.active()); - i.getStyle().imageUp = Core.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause"); - } - }).get(); + new imagebutton("icon-pause", isize, () -> { + if(Net.active()){ + ui.listfrag.toggle(); + }else{ + state.set(state.is(State.paused) ? State.playing : State.paused); + } + }).update(i -> { + if(Net.active()){ + i.getStyle().imageUp = Core.skin.getDrawable("icon-players"); + }else{ + i.setDisabled(Net.active()); + i.getStyle().imageUp = Core.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause"); + } + }).get(); - new imagebutton("icon-settings", isize, () -> { - if (Net.active() && mobile) { - if (ui.chatfrag.chatOpen()) { - ui.chatfrag.hide(); - } else { - ui.chatfrag.toggle(); - } - } else { - ui.settings.show(); - } - }).update(i -> { - if (Net.active() && mobile) { - i.getStyle().imageUp = Core.skin.getDrawable("icon-chat"); - } else { - i.getStyle().imageUp = Core.skin.getDrawable("icon-settings"); - } - }).get(); + new imagebutton("icon-settings", isize, () -> { + if(Net.active() && mobile){ + if(ui.chatfrag.chatOpen()){ + ui.chatfrag.hide(); + }else{ + ui.chatfrag.toggle(); + } + }else{ + ui.settings.show(); + } + }).update(i -> { + if(Net.active() && mobile){ + i.getStyle().imageUp = Core.skin.getDrawable("icon-chat"); + }else{ + i.getStyle().imageUp = Core.skin.getDrawable("icon-settings"); + } + }).get(); - }}.end(); + }}.end(); - row(); + row(); - new table() {{ - touchable(Touchable.enabled); - addWaveTable(); - }}.fillX().end(); + new table(){{ + touchable(Touchable.enabled); + addWaveTable(); + }}.fillX().end(); - row(); + row(); - visible(() -> !state.is(State.menu)); - row(); - new table(){{ - IntFormat fps = new IntFormat("text.fps"); - IntFormat tps = new IntFormat("text.tps"); - IntFormat ping = new IntFormat("text.ping"); - new label(() -> fps.get(Gdx.graphics.getFramesPerSecond())).padRight(10); - new label(() -> tps.get(threads.getTPS())).visible(() -> threads.isEnabled()); - row(); - new label(() -> ping.get(Net.getPing())).visible(() -> Net.client() && !gwt).colspan(2); + visible(() -> !state.is(State.menu)); + row(); + new table(){{ + IntFormat fps = new IntFormat("text.fps"); + IntFormat tps = new IntFormat("text.tps"); + IntFormat ping = new IntFormat("text.ping"); + new label(() -> fps.get(Gdx.graphics.getFramesPerSecond())).padRight(10); + new label(() -> tps.get(threads.getTPS())).visible(() -> threads.isEnabled()); + row(); + new label(() -> ping.get(Net.getPing())).visible(() -> Net.client() && !gwt).colspan(2); - infolabel = get(); - }}.size(-1).end().visible(() -> Settings.getBool("fps")); + infolabel = get(); + }}.size(-1).end().visible(() -> Settings.getBool("fps")); - }}.end(); - }}.end(); + }}.end(); + }}.end(); - new table(){{ - visible(() -> !state.is(State.menu)); - atop(); - aright(); + new table(){{ + visible(() -> !state.is(State.menu)); + atop(); + aright(); - Minimap minimap = new Minimap(); + Minimap minimap = new Minimap(); - add(minimap).visible(() -> Settings.getBool("minimap")); - }}.end(); + add(minimap).visible(() -> Settings.getBool("minimap")); + }}.end(); - //paused table - new table(){{ - visible(() -> state.is(State.paused) && !Net.active()); - atop(); + //paused table + new table(){{ + visible(() -> state.is(State.paused) && !Net.active()); + atop(); - new table("pane"){{ - new label("[orange]< "+ Bundles.get("text.paused") + " >").scale(0.75f).pad(6); - }}.end(); - }}.end(); + new table("pane"){{ + new label("[orange]< " + Bundles.get("text.paused") + " >").scale(0.75f).pad(6); + }}.end(); + }}.end(); - //respawn background table - new table("white"){{ - respawntable = get(); - respawntable.setColor(Color.CLEAR); - update(t -> { - if(state.is(State.menu)){ - respawntable.setColor(Color.CLEAR); - } - }); - }}.end(); + //respawn background table + new table("white"){{ + respawntable = get(); + respawntable.setColor(Color.CLEAR); + update(t -> { + if(state.is(State.menu)){ + respawntable.setColor(Color.CLEAR); + } + }); + }}.end(); - new table(){{ - abottom(); - visible(() -> !state.is(State.menu) && control.getSaves().isSaving()); + new table(){{ + abottom(); + visible(() -> !state.is(State.menu) && control.getSaves().isSaving()); - new label("$text.saveload"); + new label("$text.saveload"); - }}.end(); + }}.end(); - blockfrag.build(Core.scene.getRoot()); - } + blockfrag.build(Core.scene.getRoot()); + } - /**Show unlock notification for a new recipe.*/ - public void showUnlock(Recipe recipe){ - blockfrag.rebuild(); + /** + * Show unlock notification for a new recipe. + */ + public void showUnlock(Recipe recipe){ + blockfrag.rebuild(); - //if there's currently no unlock notification... - if(lastUnlockTable == null) { - Table table = new Table("button"); - table.update(() -> { - if(state.is(State.menu)){ - table.remove(); - lastUnlockLayout = null; - lastUnlockTable = null; - } - }); - table.margin(12); + //if there's currently no unlock notification... + if(lastUnlockTable == null){ + Table table = new Table("button"); + table.update(() -> { + if(state.is(State.menu)){ + table.remove(); + lastUnlockLayout = null; + lastUnlockTable = null; + } + }); + table.margin(12); - Table in = new Table(); + Table in = new Table(); - //create texture stack for displaying - Stack stack = new Stack(); - for (TextureRegion region : recipe.result.getCompactIcon()) { - Image image = new Image(region); - image.setScaling(Scaling.fit); - stack.add(image); - } + //create texture stack for displaying + Stack stack = new Stack(); + for(TextureRegion region : recipe.result.getCompactIcon()){ + Image image = new Image(region); + image.setScaling(Scaling.fit); + stack.add(image); + } - in.add(stack).size(48f).pad(2); + in.add(stack).size(48f).pad(2); - //add to table - table.add(in).padRight(8); - table.add("$text.unlocked"); - table.pack(); + //add to table + table.add(in).padRight(8); + table.add("$text.unlocked"); + table.pack(); - //create container table which will align and move - Table container = Core.scene.table(); - container.top().add(table); - container.setTranslation(0, table.getPrefHeight()); - container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(4f), - //nesting actions() calls is necessary so the right prefHeight() is used - Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.run(() ->{ - lastUnlockTable = null; - lastUnlockLayout = null; - }), Actions.removeActor()))); + //create container table which will align and move + Table container = Core.scene.table(); + container.top().add(table); + container.setTranslation(0, table.getPrefHeight()); + container.actions(Actions.translateBy(0, -table.getPrefHeight(), 1f, Interpolation.fade), Actions.delay(4f), + //nesting actions() calls is necessary so the right prefHeight() is used + Actions.run(() -> container.actions(Actions.translateBy(0, table.getPrefHeight(), 1f, Interpolation.fade), Actions.run(() -> { + lastUnlockTable = null; + lastUnlockLayout = null; + }), Actions.removeActor()))); - lastUnlockTable = container; - lastUnlockLayout = in; - }else{ - //max column size - int col = 3; - //max amount of elements minus extra 'plus' - int cap = col*col-1; + lastUnlockTable = container; + lastUnlockLayout = in; + }else{ + //max column size + int col = 3; + //max amount of elements minus extra 'plus' + int cap = col * col - 1; - //get old elements - Array elements = new Array<>(lastUnlockLayout.getChildren()); - int esize = elements.size; + //get old elements + Array elements = new Array<>(lastUnlockLayout.getChildren()); + int esize = elements.size; - //...if it's already reached the cap, ignore everything - if(esize > cap) return; + //...if it's already reached the cap, ignore everything + if(esize > cap) return; - //get size of each element - float size = 48f / Math.min(elements.size + 1, col); + //get size of each element + float size = 48f / Math.min(elements.size + 1, col); - //correct plurals if needed - if(esize == 1){ - ((Label)lastUnlockLayout.getParent().find(e -> e instanceof Label)).setText("$text.unlocked.plural"); - } + //correct plurals if needed + if(esize == 1){ + ((Label) lastUnlockLayout.getParent().find(e -> e instanceof Label)).setText("$text.unlocked.plural"); + } - lastUnlockLayout.clearChildren(); - lastUnlockLayout.defaults().size(size).pad(2); + lastUnlockLayout.clearChildren(); + lastUnlockLayout.defaults().size(size).pad(2); - for(int i = 0; i < esize && i <= cap; i ++){ - lastUnlockLayout.add(elements.get(i)); + for(int i = 0; i < esize && i <= cap; i++){ + lastUnlockLayout.add(elements.get(i)); - if(i % col == col - 1){ - lastUnlockLayout.row(); - } - } + if(i % col == col - 1){ + lastUnlockLayout.row(); + } + } - //if there's space, add it - if(esize < cap) { + //if there's space, add it + if(esize < cap){ - Stack stack = new Stack(); - for (TextureRegion region : recipe.result.getCompactIcon()) { - Image image = new Image(region); - image.setScaling(Scaling.fit); - stack.add(image); - } + Stack stack = new Stack(); + for(TextureRegion region : recipe.result.getCompactIcon()){ + Image image = new Image(region); + image.setScaling(Scaling.fit); + stack.add(image); + } - lastUnlockLayout.add(stack); - }else{ //else, add a specific icon to denote no more space - lastUnlockLayout.addImage("icon-add"); - } + lastUnlockLayout.add(stack); + }else{ //else, add a specific icon to denote no more space + lastUnlockLayout.addImage("icon-add"); + } - lastUnlockLayout.pack(); - } - } + lastUnlockLayout.pack(); + } + } - private void toggleMenus(){ - wavetable.clearActions(); - infolabel.clearActions(); + private void toggleMenus(){ + wavetable.clearActions(); + infolabel.clearActions(); - float dur = 0.3f; - Interpolation in = Interpolation.pow3Out; + float dur = 0.3f; + Interpolation in = Interpolation.pow3Out; - flip.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up"); + flip.getStyle().imageUp = Core.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up"); - if (shown) { - shown = false; - blockfrag.toggle(false, dur, in); - wavetable.actions(Actions.translateBy(0, (wavetable.getHeight() + dsize) - wavetable.getTranslation().y, dur, in)); - infolabel.actions(Actions.translateBy(0, (wavetable.getHeight()) - wavetable.getTranslation().y, dur, in)); - } else { - shown = true; - blockfrag.toggle(true, dur, in); - wavetable.actions(Actions.translateBy(0, -wavetable.getTranslation().y, dur, in)); - infolabel.actions(Actions.translateBy(0, -infolabel.getTranslation().y, dur, in)); - } - } + if(shown){ + shown = false; + blockfrag.toggle(false, dur, in); + wavetable.actions(Actions.translateBy(0, (wavetable.getHeight() + dsize) - wavetable.getTranslation().y, dur, in)); + infolabel.actions(Actions.translateBy(0, (wavetable.getHeight()) - wavetable.getTranslation().y, dur, in)); + }else{ + shown = true; + blockfrag.toggle(true, dur, in); + wavetable.actions(Actions.translateBy(0, -wavetable.getTranslation().y, dur, in)); + infolabel.actions(Actions.translateBy(0, -infolabel.getTranslation().y, dur, in)); + } + } - private String getEnemiesRemaining() { - int enemies = unitGroups[Team.red.ordinal()].size(); - if(enemies == 1) { - return Bundles.format("text.enemies.single", enemies); - } else { - return Bundles.format("text.enemies", enemies); - } - } + private String getEnemiesRemaining(){ + int enemies = unitGroups[Team.red.ordinal()].size(); + if(enemies == 1){ + return Bundles.format("text.enemies.single", enemies); + }else{ + return Bundles.format("text.enemies", enemies); + } + } - private void addWaveTable(){ - float uheight = 66f; + private void addWaveTable(){ + float uheight = 66f; - IntFormat wavef = new IntFormat("text.wave"); - IntFormat timef = new IntFormat("text.wave.waiting"); + IntFormat wavef = new IntFormat("text.wave"); + IntFormat timef = new IntFormat("text.wave.waiting"); - wavetable = new table("button"){{ - aleft(); - new table(){{ - aleft(); + wavetable = new table("button"){{ + aleft(); + new table(){{ + aleft(); - new label(() -> wavef.get(state.wave)).scale(fontScale *1.5f).left().padLeft(-6); + new label(() -> wavef.get(state.wave)).scale(fontScale * 1.5f).left().padLeft(-6); - row(); + row(); - new label(() -> unitGroups[Team.red.ordinal()].size() > 0 && state.mode.disableWaveTimer ? - getEnemiesRemaining() : - (state.mode.disableWaveTimer) ? "$text.waiting" - : timef.get((int) (state.wavetime / 60f))) - .minWidth(126).padLeft(-6).left(); + new label(() -> unitGroups[Team.red.ordinal()].size() > 0 && state.mode.disableWaveTimer ? + getEnemiesRemaining() : + (state.mode.disableWaveTimer) ? "$text.waiting" + : timef.get((int) (state.wavetime / 60f))) + .minWidth(126).padLeft(-6).left(); - margin(10f); - get().marginLeft(6); - }}.left().end(); + margin(10f); + get().marginLeft(6); + }}.left().end(); - add().growX(); + add().growX(); - playButton(uheight); - }}.height(uheight).fillX().expandX().end().get(); - wavetable.getParent().getParent().swapActor(wavetable.getParent(), menu.getParent()); - } + playButton(uheight); + }}.height(uheight).fillX().expandX().end().get(); + wavetable.getParent().getParent().swapActor(wavetable.getParent(), menu.getParent()); + } - private void playButton(float uheight){ - new imagebutton("icon-play", 30f, () -> { - if(Net.client() && players[0].isAdmin){ - Call.onAdminRequest(players[0], AdminAction.wave); - }else { - state.wavetime = 0f; - } - }).height(uheight).fillX().right().padTop(-8f).padBottom(-12f).padLeft(-15).padRight(-10).width(40f).update(l->{ - boolean vis = state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()); - boolean paused = state.is(State.paused) || !vis; + private void playButton(float uheight){ + new imagebutton("icon-play", 30f, () -> { + if(Net.client() && players[0].isAdmin){ + Call.onAdminRequest(players[0], AdminAction.wave); + }else{ + state.wavetime = 0f; + } + }).height(uheight).fillX().right().padTop(-8f).padBottom(-12f).padLeft(-15).padRight(-10).width(40f).update(l -> { + boolean vis = state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()); + boolean paused = state.is(State.paused) || !vis; - l.getStyle().imageUp = Core.skin.getDrawable(vis ? "icon-play" : "clear"); - l.setTouchable(!paused ? Touchable.enabled : Touchable.disabled); - }).visible(() -> state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()) && unitGroups[Team.red.ordinal()].size() == 0); - } + l.getStyle().imageUp = Core.skin.getDrawable(vis ? "icon-play" : "clear"); + l.setTouchable(!paused ? Touchable.enabled : Touchable.disabled); + }).visible(() -> state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()) && unitGroups[Team.red.ordinal()].size() == 0); + } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java b/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java index 3e41e10d54..4104939c22 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java @@ -10,14 +10,14 @@ import io.anuke.ucore.scene.ui.Label; import io.anuke.ucore.scene.ui.TextButton; import io.anuke.ucore.scene.ui.layout.Table; -public class LoadingFragment extends Fragment { +public class LoadingFragment extends Fragment{ private Table table; private TextButton button; @Override - public void build(Group parent) { + public void build(Group parent){ - table = new table("loadDim"){{ + table = new table("loadDim"){{ add().height(70f).row(); touchable(Touchable.enabled); @@ -33,7 +33,8 @@ public class LoadingFragment extends Fragment { row(); - button = get().addButton("$text.cancel", () -> {}).pad(20).size(250f, 70f).get(); + button = get().addButton("$text.cancel", () -> { + }).pad(20).size(250f, 70f).get(); button.setVisible(false); }}.end().get(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java index 2a9834943f..228015ea52 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java @@ -18,175 +18,175 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.*; public class MenuFragment extends Fragment{ - private Table mobileContainer; + private Table mobileContainer; - @Override - public void build(Group parent){ - new table(){{ - visible(() -> state.is(State.menu)); + @Override + public void build(Group parent){ + new table(){{ + visible(() -> state.is(State.menu)); - if(!mobile){ - buildDesktop(); - }else{ - buildMobile(); + if(!mobile){ + buildDesktop(); + }else{ + buildMobile(); - Events.on(ResizeEvent.class, () -> buildMobile()); - } - }}.end(); + Events.on(ResizeEvent.class, () -> buildMobile()); + } + }}.end(); - //discord icon in top right - if(Platform.instance.hasDiscord()) { - new table() {{ - abottom().atop().aright(); - get().addButton("", "discord", ui.discord::show).size(81, 42); - }}.end().visible(() -> state.is(State.menu)); - } + //discord icon in top right + if(Platform.instance.hasDiscord()){ + new table(){{ + abottom().atop().aright(); + get().addButton("", "discord", ui.discord::show).size(81, 42); + }}.end().visible(() -> state.is(State.menu)); + } - //info icon - if(mobile) { - new table() {{ - abottom().atop().aleft(); - get().addButton("", "info", ui.about::show).size(81, 42); - }}.end().visible(() -> state.is(State.menu)); - } + //info icon + if(mobile){ + new table(){{ + abottom().atop().aleft(); + get().addButton("", "info", ui.about::show).size(81, 42); + }}.end().visible(() -> state.is(State.menu)); + } - //version info - new table(){{ - visible(() -> state.is(State.menu)); - abottom().aleft(); - new label("Mindustry " + Version.code + " " + Version.type + " / " + Version.buildName); - }}.end(); - } + //version info + new table(){{ + visible(() -> state.is(State.menu)); + abottom().aleft(); + new label("Mindustry " + Version.code + " " + Version.type + " / " + Version.buildName); + }}.end(); + } - private void buildMobile(){ - if(mobileContainer == null){ - mobileContainer = build.getTable(); - } + private void buildMobile(){ + if(mobileContainer == null){ + mobileContainer = build.getTable(); + } - mobileContainer.clear(); - mobileContainer.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + mobileContainer.clear(); + mobileContainer.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); - float size = 120f; - float isize = 14f * 4; - mobileContainer.defaults().size(size).pad(5).padTop(4f); + float size = 120f; + float isize = 14f * 4; + mobileContainer.defaults().size(size).pad(5).padTop(4f); - MobileButton - play = new MobileButton("icon-play-2", isize, "$text.play", ui.levels::show), - maps = new MobileButton("icon-map", isize, "$text.maps", ui.maps::show), - load = new MobileButton("icon-load", isize, "$text.load", ui.load::show), - join = new MobileButton("icon-add", isize, "$text.joingame", ui.join::show), - editor = new MobileButton("icon-editor", isize, "$text.editor", () -> ui.loadAnd(ui.editor::show)), - tools = new MobileButton("icon-tools", isize, "$text.settings", ui.settings::show), - unlocks = new MobileButton("icon-unlocks", isize, "$text.unlocks", ui.unlocks::show), - donate = new MobileButton("icon-donate", isize, "$text.donate", Platform.instance::openDonations); + MobileButton + play = new MobileButton("icon-play-2", isize, "$text.play", ui.levels::show), + maps = new MobileButton("icon-map", isize, "$text.maps", ui.maps::show), + load = new MobileButton("icon-load", isize, "$text.load", ui.load::show), + join = new MobileButton("icon-add", isize, "$text.joingame", ui.join::show), + editor = new MobileButton("icon-editor", isize, "$text.editor", () -> ui.loadAnd(ui.editor::show)), + tools = new MobileButton("icon-tools", isize, "$text.settings", ui.settings::show), + unlocks = new MobileButton("icon-unlocks", isize, "$text.unlocks", ui.unlocks::show), + donate = new MobileButton("icon-donate", isize, "$text.donate", Platform.instance::openDonations); - if(Gdx.graphics.getWidth() > Gdx.graphics.getHeight()){ - mobileContainer.add(play); - mobileContainer.add(join); - mobileContainer.add(load); - mobileContainer.add(maps); - mobileContainer.row(); + if(Gdx.graphics.getWidth() > Gdx.graphics.getHeight()){ + mobileContainer.add(play); + mobileContainer.add(join); + mobileContainer.add(load); + mobileContainer.add(maps); + mobileContainer.row(); - mobileContainer.table(table -> { - table.defaults().set(mobileContainer.defaults()); + mobileContainer.table(table -> { + table.defaults().set(mobileContainer.defaults()); - table.add(editor); - table.add(tools); - table.add(unlocks); + table.add(editor); + table.add(tools); + table.add(unlocks); - if(Platform.instance.canDonate()) table.add(donate); - }).colspan(4); - }else{ - mobileContainer.add(play); - mobileContainer.add(maps); - mobileContainer.row(); - mobileContainer.add(load); - mobileContainer.add(join); - mobileContainer.row(); - mobileContainer.add(editor); - mobileContainer.add(tools); - mobileContainer.row(); + if(Platform.instance.canDonate()) table.add(donate); + }).colspan(4); + }else{ + mobileContainer.add(play); + mobileContainer.add(maps); + mobileContainer.row(); + mobileContainer.add(load); + mobileContainer.add(join); + mobileContainer.row(); + mobileContainer.add(editor); + mobileContainer.add(tools); + mobileContainer.row(); - mobileContainer.table(table -> { - table.defaults().set(mobileContainer.defaults()); + mobileContainer.table(table -> { + table.defaults().set(mobileContainer.defaults()); - table.add(unlocks); + table.add(unlocks); - if(Platform.instance.canDonate()) table.add(donate); - }).colspan(2); - } - } + if(Platform.instance.canDonate()) table.add(donate); + }).colspan(2); + } + } - private void buildDesktop(){ - new table(){{ + private void buildDesktop(){ + new table(){{ - float w = 200f; - float bw = w * 2f + 10f; + float w = 200f; + float bw = w * 2f + 10f; - defaults().size(w, 66f).padTop(5).padRight(5); + defaults().size(w, 66f).padTop(5).padRight(5); - add(new MenuButton("icon-play-2", "$text.play", MenuFragment.this::showPlaySelect)).width(bw).colspan(2); + add(new MenuButton("icon-play-2", "$text.play", MenuFragment.this::showPlaySelect)).width(bw).colspan(2); - row(); + row(); - add(new MenuButton("icon-editor", "$text.editor", () -> ui.loadAnd(ui.editor::show))); + add(new MenuButton("icon-editor", "$text.editor", () -> ui.loadAnd(ui.editor::show))); - add(new MenuButton("icon-map", "$text.maps", ui.maps::show)); + add(new MenuButton("icon-map", "$text.maps", ui.maps::show)); - row(); + row(); - add(new MenuButton("icon-info", "$text.about.button", ui.about::show)); + add(new MenuButton("icon-info", "$text.about.button", ui.about::show)); - add(new MenuButton("icon-tools", "$text.settings", ui.settings::show)); + add(new MenuButton("icon-tools", "$text.settings", ui.settings::show)); - row(); + row(); - add(new MenuButton("icon-menu", "$text.changelog.title", ui.changelog::show)); + add(new MenuButton("icon-menu", "$text.changelog.title", ui.changelog::show)); - add(new MenuButton("icon-unlocks", "$text.unlocks", ui.unlocks::show)); + add(new MenuButton("icon-unlocks", "$text.unlocks", ui.unlocks::show)); - row(); + row(); - if(!gwt){ - add(new MenuButton("icon-exit", "$text.quit", Gdx.app::exit)).width(bw).colspan(2); - } + if(!gwt){ + add(new MenuButton("icon-exit", "$text.quit", Gdx.app::exit)).width(bw).colspan(2); + } - get().margin(16); - }}.end(); - } + get().margin(16); + }}.end(); + } - private void showPlaySelect(){ - float w = 200f; - float bw = w * 2f + 10f; + private void showPlaySelect(){ + float w = 200f; + float bw = w * 2f + 10f; - FloatingDialog dialog = new FloatingDialog("$text.play"); - dialog.addCloseButton(); - dialog.content().defaults().height(66f).width(w).padRight(5f); + FloatingDialog dialog = new FloatingDialog("$text.play"); + dialog.addCloseButton(); + dialog.content().defaults().height(66f).width(w).padRight(5f); - dialog.content().add(new MenuButton("icon-play-2", "$text.newgame", () -> { - dialog.hide(); - ui.levels.show(); - })).width(bw).colspan(2); - dialog.content().row(); + dialog.content().add(new MenuButton("icon-play-2", "$text.newgame", () -> { + dialog.hide(); + ui.levels.show(); + })).width(bw).colspan(2); + dialog.content().row(); - dialog.content().add(new MenuButton("icon-add", "$text.joingame", () -> { - if(Platform.instance.canJoinGame()){ - ui.join.show(); - dialog.hide(); - }else{ - ui.showInfo("$text.multiplayer.web"); - } - })); + dialog.content().add(new MenuButton("icon-add", "$text.joingame", () -> { + if(Platform.instance.canJoinGame()){ + ui.join.show(); + dialog.hide(); + }else{ + ui.showInfo("$text.multiplayer.web"); + } + })); - dialog.content().add(new MenuButton("icon-tutorial", "$text.tutorial", ()-> ui.showInfo("The tutorial is currently not yet implemented."))); + dialog.content().add(new MenuButton("icon-tutorial", "$text.tutorial", () -> ui.showInfo("The tutorial is currently not yet implemented."))); - dialog.content().row(); + dialog.content().row(); - dialog.content().add(new MenuButton("icon-load", "$text.loadgame", () -> { - ui.load.show(); - dialog.hide(); - })).width(bw).colspan(2); + dialog.content().add(new MenuButton("icon-load", "$text.loadgame", () -> { + ui.load.show(); + dialog.hide(); + })).width(bw).colspan(2); - dialog.show(); - } + dialog.show(); + } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/OverlayFragment.java b/core/src/io/anuke/mindustry/ui/fragments/OverlayFragment.java index 08cfff42c6..fd861518ad 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/OverlayFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/OverlayFragment.java @@ -3,10 +3,13 @@ package io.anuke.mindustry.ui.fragments; import io.anuke.mindustry.input.InputHandler; import io.anuke.ucore.scene.Group; -/**Fragment for displaying overlays such as block inventories. One is created for each input handler.*/ +/** + * Fragment for displaying overlays such as block inventories. One is created for each input handler. + */ public class OverlayFragment extends Fragment{ public final BlockInventoryFragment inv; public final BlockConfigFragment config; + public final BlockConsumeFragment consume; private Group group = new Group(); private InputHandler input; @@ -16,6 +19,7 @@ public class OverlayFragment extends Fragment{ inv = new BlockInventoryFragment(input); config = new BlockConfigFragment(input); + consume = new BlockConsumeFragment(); } @Override @@ -25,6 +29,7 @@ public class OverlayFragment extends Fragment{ inv.build(group); config.build(group); + consume.build(group); input.buildUI(group); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java index 08f8780a47..584fef1b94 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java @@ -116,26 +116,26 @@ public class PlayerListFragment extends Fragment{ button.labelWrap("[#" + player.color.toString().toUpperCase() + "]" + player.name).width(170f).pad(10); button.add().grow(); - button.addImage("icon-admin").size(14*2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5); + button.addImage("icon-admin").size(14 * 2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5); if((Net.server() || players[0].isAdmin) && !player.isLocal && (!player.isAdmin || Net.server())){ button.add().growY(); - float bs = (h + 14)/2f; + float bs = (h + 14) / 2f; button.table(t -> { t.defaults().size(bs - 1, bs + 3); //TODO requests. - t.addImageButton("icon-ban", 14*2, () -> { + t.addImageButton("icon-ban", 14 * 2, () -> { ui.showConfirm("$text.confirm", "$text.confirmban", () -> Call.onAdminRequest(player, AdminAction.ban)); }).padBottom(-5.1f); - t.addImageButton("icon-cancel", 14*2, () -> Call.onAdminRequest(player, AdminAction.kick)).padBottom(-5.1f); + t.addImageButton("icon-cancel", 14 * 2, () -> Call.onAdminRequest(player, AdminAction.kick)).padBottom(-5.1f); t.row(); - t.addImageButton("icon-admin", "toggle", 14*2, () -> { + t.addImageButton("icon-admin", "toggle", 14 * 2, () -> { if(Net.client()) return; String id = netServer.admins.getTraceByID(player.uuid).uuid; @@ -154,7 +154,7 @@ public class PlayerListFragment extends Fragment{ b.setDisabled(Net.client()); }).get().setTouchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled); - t.addImageButton("icon-zoom-small", 14*2, () -> Call.onAdminRequest(player, AdminAction.trace)); + t.addImageButton("icon-zoom-small", 14 * 2, () -> Call.onAdminRequest(player, AdminAction.trace)); }).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs); diff --git a/core/src/io/anuke/mindustry/world/BarType.java b/core/src/io/anuke/mindustry/world/BarType.java index 332ed5c7a1..e5ed5a6d3b 100644 --- a/core/src/io/anuke/mindustry/world/BarType.java +++ b/core/src/io/anuke/mindustry/world/BarType.java @@ -2,7 +2,7 @@ package io.anuke.mindustry.world; import com.badlogic.gdx.graphics.Color; -public enum BarType { +public enum BarType{ health(Color.SCARLET), inventory(Color.GREEN), power(Color.valueOf("fbeb67")), diff --git a/core/src/io/anuke/mindustry/world/BaseBlock.java b/core/src/io/anuke/mindustry/world/BaseBlock.java index 9087faf510..466996ddae 100644 --- a/core/src/io/anuke/mindustry/world/BaseBlock.java +++ b/core/src/io/anuke/mindustry/world/BaseBlock.java @@ -1,27 +1,42 @@ package io.anuke.mindustry.world; -import com.badlogic.gdx.math.GridPoint2; +import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.content.fx.EnvironmentFx; +import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.consumers.ConsumeItem; +import io.anuke.mindustry.world.consumers.ConsumeLiquid; +import io.anuke.mindustry.world.consumers.Consumers; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Translator; -public abstract class BaseBlock { +public abstract class BaseBlock{ public boolean hasItems; public boolean hasLiquids; public boolean hasPower; + public boolean outputsLiquid = false; + public boolean singleLiquid = true; + public int itemCapacity; public float liquidCapacity = 10f; public float liquidFlowFactor = 4.9f; public float powerCapacity = 10f; - /**Returns the amount of items this block can accept.*/ + public Consumers consumes = new Consumers(); + + public boolean shouldConsume(Tile tile){ + return true; + } + + /** + * Returns the amount of items this block can accept. + */ public int acceptStack(Item item, int amount, Tile tile, Unit source){ if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){ return Math.min(getMaximumAccepted(tile, item), amount); @@ -31,54 +46,61 @@ public abstract class BaseBlock { } public int getMaximumAccepted(Tile tile, Item item){ - return itemCapacity - tile.entity.items.totalItems(); + return itemCapacity - tile.entity.items.total(); } - /**Remove a stack from this inventory, and return the amount removed.*/ + /** + * Remove a stack from this inventory, and return the amount removed. + */ public int removeStack(Tile tile, Item item, int amount){ tile.entity.wakeUp(); - tile.entity.items.removeItem(item, amount); + tile.entity.items.remove(item, amount); return amount; } - /**Handle a stack input.*/ + /** + * Handle a stack input. + */ public void handleStack(Item item, int amount, Tile tile, Unit source){ tile.entity.wakeUp(); - tile.entity.items.addItem(item, amount); + tile.entity.items.add(item, amount); } - /**Returns offset for stack placement.*/ + /** + * Returns offset for stack placement. + */ public void getStackOffset(Item item, Tile tile, Translator trns){ } + public void onProximityUpdate(Tile tile){ + } + public void handleItem(Item item, Tile tile, Tile source){ - tile.entity.items.addItem(item, 1); + tile.entity.items.add(item, 1); } public boolean acceptItem(Item item, Tile tile, Tile source){ - return false; + return tile.entity != null && consumes.has(ConsumeItem.class) && consumes.item() == item && tile.entity.items.total() < itemCapacity; } public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return tile.entity.liquids.amount + amount < liquidCapacity - && (tile.entity.liquids.liquid == liquid || tile.entity.liquids.amount <= 0.1f); - } - - public float handleAuxLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return 0f; + return hasLiquids && tile.entity.liquids.get(liquid) + amount < liquidCapacity && + (!singleLiquid || (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.01f)) + && (!consumes.has(ConsumeLiquid.class) || consumes.liquid() == liquid); } public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - tile.entity.liquids.liquid = liquid; - tile.entity.liquids.amount += amount; + tile.entity.liquids.add(liquid, amount); } public boolean acceptPower(Tile tile, Tile source, float amount){ return true; } - /**Returns how much power is accepted.*/ + /** + * Returns how much power is accepted. + */ public float addPower(Tile tile, float amount){ float canAccept = Math.min(powerCapacity - tile.entity.power.amount, amount); @@ -87,102 +109,90 @@ public abstract class BaseBlock { return canAccept; } - public void tryDumpLiquid(Tile tile){ - if(tile.entity.liquids.amount < 0.001f) return; + public void tryDumpLiquid(Tile tile, Liquid liquid){ + Array proximity = tile.entity.proximity(); + int dump = tile.getDump(); - int size = tile.block().size; + for(int i = 0; i < proximity.size; i++){ + incrementDump(tile, proximity.size); + Tile other = proximity.get((i + dump) % proximity.size); + Tile in = Edges.getFacingEdge(tile, other); - GridPoint2[] nearby = Edges.getEdges(size); - byte i = tile.getDump(); + if(other.block().hasLiquids){ + float ofract = other.entity.liquids.get(liquid) / other.block().liquidCapacity; + float fract = tile.entity.liquids.get(liquid) / liquidCapacity; - for (int j = 0; j < nearby.length; j ++) { - Tile other = tile.getNearby(nearby[i]); - Tile in = tile.getNearby(Edges.getInsideEdges(size)[i]); - - if(other != null) other = other.target(); - - if (other != null && other.block().hasLiquids) { - float ofract = other.entity.liquids.amount / other.block().liquidCapacity; - float fract = tile.entity.liquids.amount / liquidCapacity; - - if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f); + if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f, liquid); } - - i = (byte) ((i + 1) % nearby.length); } } - public void tryMoveLiquid(Tile tile, Tile tileSource, Tile next, float amount){ - float flow = Math.min(next.block().liquidCapacity - next.entity.liquids.amount - 0.001f, amount); + public void tryMoveLiquid(Tile tile, Tile tileSource, Tile next, float amount, Liquid liquid){ + float flow = Math.min(next.block().liquidCapacity - next.entity.liquids.get(liquid) - 0.001f, amount); - if(next.block().acceptLiquid(next, tileSource, tile.entity.liquids.liquid, flow)){ - next.block().handleLiquid(next, tileSource, tile.entity.liquids.liquid, flow); - tile.entity.liquids.amount -= flow; + if(next.block().acceptLiquid(next, tileSource, liquid, flow)){ + next.block().handleLiquid(next, tileSource, liquid, flow); + tile.entity.liquids.remove(liquid, flow); } } - public float tryMoveLiquid(Tile tile, Tile next, boolean leak){ + public float tryMoveLiquid(Tile tile, Tile next, boolean leak, Liquid liquid){ if(next == null) return 0; next = next.target(); - if(next.block().hasLiquids && tile.entity.liquids.amount > 0f){ + if(next.block().hasLiquids && tile.entity.liquids.get(liquid) > 0f){ - if((next.entity.liquids.liquid == tile.entity.liquids.liquid || next.entity.liquids.amount <= 0.01f) && - next.block().acceptLiquid(next, tile, tile.entity.liquids.liquid, 0f)) { - float ofract = next.entity.liquids.amount / next.block().liquidCapacity; - float fract = tile.entity.liquids.amount / liquidCapacity; - float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids.amount); - flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids.amount - 0.001f); + if(next.block().acceptLiquid(next, tile, liquid, 0f)){ + float ofract = next.entity.liquids.get(liquid) / next.block().liquidCapacity; + float fract = tile.entity.liquids.get(liquid) / liquidCapacity; + float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids.get(liquid)); + flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids.get(liquid) - 0.001f); - if (flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, tile.entity.liquids.liquid, flow)) { - next.block().handleLiquid(next, tile, tile.entity.liquids.liquid, flow); - tile.entity.liquids.amount -= flow; + if(flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, liquid, flow)){ + next.block().handleLiquid(next, tile, liquid, flow); + tile.entity.liquids.remove(liquid, flow); return flow; - } else if (ofract > 0.1f && fract > 0.1f) { - Liquid liquid = tile.entity.liquids.liquid, other = next.entity.liquids.liquid; - if ((other.flammability > 0.3f && liquid.temperature > 0.7f) || - (liquid.flammability > 0.3f && other.temperature > 0.7f)) { + }else if(ofract > 0.1f && fract > 0.1f){ + Liquid other = next.entity.liquids.current(); + if((other.flammability > 0.3f && liquid.temperature > 0.7f) || + (liquid.flammability > 0.3f && other.temperature > 0.7f)){ tile.entity.damage(1 * Timers.delta()); next.entity.damage(1 * Timers.delta()); - if (Mathf.chance(0.1 * Timers.delta())) { + if(Mathf.chance(0.1 * Timers.delta())){ Effects.effect(EnvironmentFx.fire, (tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); } - } else if ((liquid.temperature > 0.7f && other.temperature < 0.55f) || - (other.temperature > 0.7f && liquid.temperature < 0.55f)) { - tile.entity.liquids.amount -= Math.min(tile.entity.liquids.amount, 0.7f * Timers.delta()); - if (Mathf.chance(0.2f * Timers.delta())) { + }else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || + (other.temperature > 0.7f && liquid.temperature < 0.55f)){ + tile.entity.liquids.remove(liquid, Math.min(tile.entity.liquids.get(liquid), 0.7f * Timers.delta())); + if(Mathf.chance(0.2f * Timers.delta())){ Effects.effect(EnvironmentFx.steam, (tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); } } } - }else{ - float accepted = next.block().handleAuxLiquid(next, tile, tile.entity.liquids.liquid, tile.entity.liquids.amount); - tile.entity.liquids.amount -= accepted; } }else if(leak && !next.block().solid && !next.block().hasLiquids){ - float leakAmount = Math.min(tile.entity.liquids.amount, tile.entity.liquids.amount/1.5f); - Puddle.deposit(next, tile, tile.entity.liquids.liquid, leakAmount); - tile.entity.liquids.amount -= leakAmount; + float leakAmount = tile.entity.liquids.get(liquid) / 1.5f; + Puddle.deposit(next, tile, liquid, leakAmount); + tile.entity.liquids.remove(liquid, leakAmount); } return 0; } /** * Tries to put this item into a nearby container, if there are no available - * containers, it gets added to the block's inventory.*/ + * containers, it gets added to the block's inventory. + */ public void offloadNear(Tile tile, Item item){ - int size = tile.block().size; + Array proximity = tile.entity.proximity(); + int dump = tile.getDump(); - GridPoint2[] nearby = Edges.getEdges(size); - byte i = (byte)(tile.getDump() % nearby.length); - - for(int j = 0; j < nearby.length; j ++){ - tile.setDump((byte)((i + 1) % nearby.length)); - Tile other = tile.getNearby(nearby[i]); - Tile in = tile.getNearby(Edges.getInsideEdges(size)[i]); - if(other != null && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ + for(int i = 0; i < proximity.size; i++){ + incrementDump(tile, proximity.size); + Tile other = proximity.get((i + dump) % proximity.size); + Tile in = Edges.getFacingEdge(tile, other); + if(other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ other.block().handleItem(item, other, in); return; } @@ -191,48 +201,67 @@ public abstract class BaseBlock { handleItem(item, tile, tile); } - /**Try dumping any item near the tile.*/ + /** + * Try dumping any item near the tile. + */ public boolean tryDump(Tile tile){ return tryDump(tile, null); } - /**Try dumping a specific item near the tile.*/ + /** + * Try dumping a specific item near the tile. + * + * @param todump Item to dump. Can be null to dump anything. + */ public boolean tryDump(Tile tile, Item todump){ - if(tile.entity == null || !hasItems) return false; + TileEntity entity = tile.entity; + if(entity == null || !hasItems || tile.entity.items.total() == 0 || (todump != null && !entity.items.has(todump))) + return false; - int size = tile.block().size; + Array proximity = entity.proximity(); + int dump = tile.getDump(); - GridPoint2[] nearby = Edges.getEdges(size); - byte i = (byte)(tile.getDump() % nearby.length); + if(proximity.size == 0) return false; - for(int j = 0; j < nearby.length; j ++){ - Tile other; - Tile in; + for(int i = 0; i < proximity.size; i++){ + Tile other = proximity.get((i + dump) % proximity.size); + Tile in = Edges.getFacingEdge(tile, other); - for(int ii = 0; ii < Item.all().size; ii ++){ - Item item = Item.getByID(ii); - other = tile.getNearby(nearby[i]); - in = tile.getNearby(Edges.getInsideEdges(size)[i]); + if(todump == null){ - if(todump != null && item != todump) continue; + for(int ii = 0; ii < Item.all().size; ii++){ + Item item = Item.getByID(ii); - if(tile.entity.items.hasItem(item) && other != null && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ - other.block().handleItem(item, other, in); - tile.entity.items.removeItem(item, 1); - i = (byte)((i + 1) % nearby.length); - tile.setDump(i); + if(entity.items.has(item) && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ + other.block().handleItem(item, other, in); + tile.entity.items.remove(item, 1); + incrementDump(tile, proximity.size); + return true; + } + } + }else{ + + if(other.block().acceptItem(todump, other, in) && canDump(tile, other, todump)){ + other.block().handleItem(todump, other, in); + tile.entity.items.remove(todump, 1); + incrementDump(tile, proximity.size); return true; } } - i = (byte)((i + 1) % nearby.length); - tile.setDump(i); + incrementDump(tile, proximity.size); } return false; } - /**Used for dumping items.*/ + private void incrementDump(Tile tile, int prox){ + tile.setDump((byte) ((tile.getDump() + 1) % prox)); + } + + /** + * Used for dumping items. + */ public boolean canDump(Tile tile, Tile to, Item item){ return true; } diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 987041b034..a8961072a4 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -5,7 +5,6 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.reflect.ClassReflection; -import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.Damage; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.TileEntity; @@ -20,7 +19,6 @@ import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.input.CursorType; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.ItemStack; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.meta.*; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; @@ -31,371 +29,395 @@ import io.anuke.ucore.util.Bundles; import io.anuke.ucore.util.EnumSet; import io.anuke.ucore.util.Mathf; -import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.tilesize; +import static io.anuke.mindustry.Vars.world; public class Block extends BaseBlock implements Content{ - private static int lastid; - private static Array blocks = new Array<>(140); - private static ObjectMap map = new ObjectMap<>(); + private static int lastid; + private static Array blocks = new Array<>(140); + private static ObjectMap map = new ObjectMap<>(); + /** internal name */ + public final String name; + /** internal ID */ + public final int id; + /** display name */ + public final String formalName; + /** Detailed description of the block. Can be as long as necesary. */ + public final String fullDescription; + /** whether this block has a tile entity that updates */ + public boolean update; + /** whether this block has health and can be destroyed */ + public boolean destructible; + /** if true, this block cannot be broken by normal means. */ + public boolean unbreakable; + /** whether this is solid */ + public boolean solid; + /** whether this block CAN be solid. */ + public boolean solidifes; + /** whether this is rotateable */ + public boolean rotate; + /** whether you can break this with rightclick */ + public boolean breakable; + /** whether this floor can be placed on. */ + public boolean placeableOn = true; + /** tile entity health */ + public int health = -1; + /** base block explosiveness */ + public float baseExplosiveness = 0f; + /** whether this block can be placed on liquids. */ + public boolean floating = true; + /** stuff that drops when broken */ + public ItemStack drops = null; + /** multiblock size */ + public int size = 1; + /** Whether to draw this block in the expanded draw range. */ + public boolean expanded = false; + /** Max of timers used. */ + public int timers = 0; + /** Cache layer. Only used for 'cached' rendering. */ + public CacheLayer cacheLayer = CacheLayer.normal; + /** Layer to draw extra stuff on. */ + public Layer layer = null; + /** Extra layer to draw extra extra stuff on. */ + public Layer layer2 = null; + /** whether this block can be replaced in all cases */ + public boolean alwaysReplace = false; + /** whether this block has instant transfer checking. used for calculations to prevent infinite loops. */ + public boolean instantTransfer = false; + /** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */ + public BlockGroup group = BlockGroup.none; + /** list of displayed block status bars. Defaults to health bar. */ + public BlockBars bars = new BlockBars(); + /** List of block stats. */ + public BlockStats stats = new BlockStats(this); + /** List of block flags. Used for AI indexing. */ + public EnumSet flags; + /** Whether to automatically set the entity to 'sleeping' when created. */ + public boolean autoSleep; + /** Name of shadow region to load. Null to indicate normal shadow. */ + public String shadow = null; + /** Whether the block can be tapped and selected to configure. */ + public boolean configurable; + /** Whether this block consumes touchDown events when tapped. */ + public boolean consumesTap; + /** The color of this block when displayed on the minimap or map preview. */ + public Color minimapColor = Color.CLEAR; + /** View range of this block type. Use a value < 0 to disable. */ + public float viewRange = 10; + protected Array tempTiles = new Array<>(); + protected Color tempColor = new Color(); + protected TextureRegion[] blockIcon; + protected TextureRegion[] icon; + protected TextureRegion[] compactIcon; + protected TextureRegion editorIcon; + protected TextureRegion shadowRegion; + protected TextureRegion region; - protected Array tempTiles = new Array<>(); - protected Color tempColor = new Color(); + public Block(String name){ + this.name = name; + this.formalName = Bundles.get("block." + name + ".name", name); + this.fullDescription = Bundles.getOrNull("block." + name + ".description"); + this.solid = false; + this.id = lastid++; - protected TextureRegion[] blockIcon; - protected TextureRegion[] icon; - protected TextureRegion[] compactIcon; - protected TextureRegion editorIcon; - - /**internal name*/ - public final String name; - /**internal ID*/ - public final int id; - /**display name*/ - public final String formalName; - /**whether this block has a tile entity that updates*/ - public boolean update; - /**whether this block has health and can be destroyed*/ - public boolean destructible; - /**if true, this block cannot be broken by normal means.*/ - public boolean unbreakable; - /**whether this is solid*/ - public boolean solid; - /**whether this block CAN be solid.*/ - public boolean solidifes; - /**whether this is rotateable*/ - public boolean rotate; - /**whether you can break this with rightclick*/ - public boolean breakable; - /**whether this floor can be placed on.*/ - public boolean placeableOn = true; - /**tile entity health*/ - public int health = -1; - /**base block explosiveness*/ - public float baseExplosiveness = 0f; - /**whether to display a different shadow per variant*/ - public boolean varyShadow = false; - /**whether this block can be placed on liquids.*/ - public boolean floating = true; - /**number of block variants, 0 to disable*/ - public int variants = 0; - /**stuff that drops when broken*/ - public ItemStack drops = null; - /**multiblock size*/ - public int size = 1; - /**Detailed description of the block. Can be as long as necesary.*/ - public final String fullDescription; - /**Whether to draw this block in the expanded draw range.*/ - public boolean expanded = false; - /**Max of timers used.*/ - public int timers = 0; - /**Cache layer. Only used for 'cached' rendering.*/ - public CacheLayer cacheLayer = CacheLayer.normal; - /**Layer to draw extra stuff on.*/ - public Layer layer = null; - /**Extra layer to draw extra extra stuff on.*/ - public Layer layer2 = null; - /**whether this block can be replaced in all cases*/ - public boolean alwaysReplace = false; - /**whether this block has instant transfer checking. used for calculations to prevent infinite loops.*/ - public boolean instantTransfer = false; - /**The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other.*/ - public BlockGroup group = BlockGroup.none; - /**list of displayed block status bars. Defaults to health bar.*/ - public BlockBars bars = new BlockBars(); - /**List of block stats.*/ - public BlockStats stats = new BlockStats(); - /**List of block flags. Used for AI indexing.*/ - public EnumSet flags; - /**Whether to automatically set the entity to 'sleeping' when created.*/ - public boolean autoSleep; - /**Name of shadow region to load. Null to indicate normal shadow.*/ - public String shadow = null; - /**Region used for drawing shadows.*/ - public TextureRegion shadowRegion; - /**Texture region array for drawing multiple shadows.*/ - public TextureRegion[] shadowRegions; - /**Whether the block can be tapped and selected to configure.*/ - public boolean configurable; - /**Whether this block consumes touchDown events when tapped.*/ - public boolean consumesTap; - /**The color of this block when displayed on the minimap or map preview.*/ - public Color minimapColor = Color.CLEAR; - /**View range of this block type. Use a value < 0 to disable.*/ - public float viewRange = 10; - - public Block(String name) { - this.name = name; - this.formalName = Bundles.get("block." + name + ".name", name); - this.fullDescription = Bundles.getOrNull("block." + name + ".description"); - this.solid = false; - this.id = lastid++; - - if(map.containsKey(name)){ - throw new RuntimeException("Two blocks cannot have the same names! Problematic block: " + name); - } - - map.put(name, this); - blocks.add(this); - } - - public boolean isLayer(Tile tile){return true;} - public boolean isLayer2(Tile tile){return true;} - public void drawLayer(Tile tile){} - public void drawLayer2(Tile tile){} - - /**Draw the block overlay that is shown when a cursor is over the block.*/ - public void drawSelect(Tile tile){} - - /**Drawn when you are placing a block.*/ - public void drawPlace(int x, int y, int rotation, boolean valid){} - - /**Called after the block is placed.*/ - public void placed(Tile tile){} - - /**Called every frame a unit is on this tile.*/ - public void unitOn(Tile tile, Unit unit){} - - /**Returns whether ot not this block can be place on the specified tile.*/ - public boolean canPlaceOn(Tile tile){ return true; } - - /**Called after all blocks are created.*/ - @Override - public void init(){ - //initialize default health based on size - if(health == -1){ - health = size*size*40; - } - - setStats(); - setBars(); - } - - @Override - public void load() { - shadowRegion = Draw.region(shadow == null ? "shadow-" + size : shadow); - - if(varyShadow && variants > 0) { - shadowRegions = new TextureRegion[variants]; - for(int i = 0; i < variants; i ++){ - shadowRegions[i] = Draw.region(name + "shadow" + (i + 1)); - } - } - } - - /**Called when the block is tapped.*/ - public void tapped(Tile tile, Player player){ - - } - - /**Returns whether or not a hand cursor should be shown over this block.*/ - public CursorType getCursor(Tile tile){ - return configurable ? CursorType.hand : CursorType.normal; - } - - /**Called when this block is tapped to build a UI on the table. - * {@link #configurable} able} must return true for this to be called.*/ - public void buildTable(Tile tile, Table table) {} - - /**Called when another tile is tapped while this block is selected. - * Returns whether or not this block should be deselected.*/ - public boolean onConfigureTileTapped(Tile tile, Tile other){ - return tile != other; - } - - /**Returns whether this config menu should show when the specified player taps it.*/ - public boolean shouldShowConfigure(Tile tile, Player player){ - return true; - } - - /**Whether this configuration should be hidden now. Called every frame the config is open.*/ - public boolean shouldHideConfigure(Tile tile, Player player){ - return false; - } - - public boolean synthetic(){ - return update || destructible || solid; - } - - public void drawConfigure(Tile tile){ - Draw.color(Palette.accent); - Lines.stroke(1f); - Lines.square(tile.drawx(), tile.drawy(), - tile.block().size * tilesize / 2f + 1f); - Draw.reset(); - } - - public void setStats(){ - stats.add(BlockStat.size, "{0}x{0}", size); - stats.add(BlockStat.health, health, StatUnit.none); - - if(hasPower) stats.add(BlockStat.powerCapacity, powerCapacity, StatUnit.powerUnits); - if(hasLiquids) stats.add(BlockStat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits); - if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items); - } - - //TODO make this easier to config. - public void setBars(){ - if(hasPower) bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.amount / powerCapacity)); - if(hasLiquids) bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.amount / liquidCapacity)); - if(hasItems) bars.add(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity.items.totalItems() / itemCapacity)); - } - - public String name(){ - return name; - } - - public boolean isSolidFor(Tile tile){ - return false; - } - - public boolean canReplace(Block other){ - return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group; - } - - public float handleDamage(Tile tile, float amount){ - return amount; - } - - public void handleBulletHit(TileEntity entity, Bullet bullet){ - entity.damage(bullet.getDamage()); - } - - public void update(Tile tile){} - - public boolean isAccessible(){ - return (hasItems && itemCapacity > 0); - } - - /**Called after the block is destroyed and removed.*/ - public void afterDestroyed(Tile tile, TileEntity entity){ - - } - - /**Called when the block is destroyed.*/ - public void onDestroyed(Tile tile){ - float x = tile.worldx(), y = tile.worldy(); - float explosiveness = baseExplosiveness; - float flammability = 0f; - float heat = 0f; - float power = 0f; - int units = 1; - tempColor.set(Palette.darkFlame); - - if(hasItems){ - for(Item item : Item.all()){ - int amount = tile.entity.items.getItem(item); - explosiveness += item.explosiveness*amount; - flammability += item.flammability*amount; - - if(item.flammability*amount > 0.5){ - units ++; - Hue.addu(tempColor, item.flameColor); - } - } - } - - if(hasLiquids){ - float amount = tile.entity.liquids.amount; - explosiveness += tile.entity.liquids.liquid.explosiveness*amount/2f; - flammability += tile.entity.liquids.liquid.flammability*amount/2f; - heat += Mathf.clamp(tile.entity.liquids.liquid.temperature-0.5f)*amount/2f; - - if(tile.entity.liquids.liquid.flammability*amount > 2f){ - units ++; - Hue.addu(tempColor, tile.entity.liquids.liquid.flameColor); - } - } - - if(hasPower){ - power += tile.entity.power.amount; - } - - tempColor.mul(1f/units); - - if(hasLiquids) { - - Liquid liquid = tile.entity.liquids.liquid; - float splash = Mathf.clamp(tile.entity.liquids.amount / 4f, 0f, 10f); - - for (int i = 0; i < Mathf.clamp(tile.entity.liquids.amount / 5, 0, 30); i++) { - Timers.run(i / 2, () -> { - Tile other = world.tile(tile.x + Mathf.range(size / 2), tile.y + Mathf.range(size / 2)); - if (other != null) { - Puddle.deposit(other, liquid, splash); - } - }); - } - } - - Damage.dynamicExplosion(x, y, flammability, explosiveness, power, tilesize * size/2f, tempColor); - if(!tile.floor().solid && !tile.floor().isLiquid){ - RubbleDecal.create(tile.drawx(), tile.drawy(), size); - } - } - - /**Returns the flammability of the tile. Used for fire calculations. - * Takes flammability of floor liquid into account.*/ - public float getFlammability(Tile tile){ - if(!hasItems || tile.entity == null){ - if(tile.floor().isLiquid && !solid){ - return tile.floor().liquidDrop.flammability; - } - return 0; - }else{ - float result = 0f; - for (int i = 0; i < Item.all().size; i++) { - int amount = tile.entity.items.items[i]; - result += Item.getByID(i).flammability*amount; - } - if(hasLiquids){ - result += tile.entity.liquids.amount * tile.entity.liquids.liquid.flammability/3f; - } - return result; - } - } - - public TextureRegion getEditorIcon(){ - if(editorIcon == null){ - editorIcon = Draw.region("block-icon-" + name, Draw.region("clear")); - } - return editorIcon; - } - - /**Returns the icon used for displaying this block in the place menu*/ - public TextureRegion[] getIcon(){ - if(icon == null) { - if (Draw.hasRegion(name + "-icon")) { - icon = new TextureRegion[]{Draw.region(name + "-icon")}; - } else if (Draw.hasRegion(name)){ - icon = new TextureRegion[]{Draw.region(name)}; - } else if (Draw.hasRegion(name + "1")) { - icon = new TextureRegion[]{Draw.region(name + "1")}; - }else{ - icon = new TextureRegion[]{}; - } + if(map.containsKey(name)){ + throw new RuntimeException("Two blocks cannot have the same names! Problematic block: " + name); } - return icon; - } - - /**Returns a list of regions that represent this block in the world*/ - public TextureRegion[] getBlockIcon(){ - return getIcon(); + map.put(name, this); + blocks.add(this); } - /**Returns a list of icon regions that have been cropped to 8x8*/ - public TextureRegion[] getCompactIcon(){ - if(compactIcon == null) { - compactIcon = new TextureRegion[getIcon().length]; - for (int i = 0; i < compactIcon.length; i++) { - compactIcon[i] = iconRegion(getIcon()[i]); - } - } - return compactIcon; - } + public static Array all(){ + return blocks; + } - /**Crops a regionto 8x8*/ - protected TextureRegion iconRegion(TextureRegion src){ + public static Block getByName(String name){ + return map.get(name); + } + + public static Block getByID(int id){ + if(id < 0){ //offset negative values by 256, as they are a product of byte overflow + id += 256; + } + if(id >= blocks.size || id < 0){ + throw new RuntimeException("No block with ID '" + id + "' found!"); + } + return blocks.get(id); + } + + public boolean isLayer(Tile tile){ + return true; + } + + public boolean isLayer2(Tile tile){ + return true; + } + + public void drawLayer(Tile tile){ + } + + public void drawLayer2(Tile tile){ + } + + /** Draw the block overlay that is shown when a cursor is over the block. */ + public void drawSelect(Tile tile){ + } + + /** Drawn when you are placing a block. */ + public void drawPlace(int x, int y, int rotation, boolean valid){ + } + + /** Called after the block is placed. */ + public void placed(Tile tile){ + } + + /** Called every frame a unit is on this tile. */ + public void unitOn(Tile tile, Unit unit){ + } + + /** Returns whether ot not this block can be place on the specified tile. */ + public boolean canPlaceOn(Tile tile){ + return true; + } + + /** Called after all blocks are created. */ + @Override + public void init(){ + //initialize default health based on size + if(health == -1){ + health = size * size * 40; + } + + setStats(); + setBars(); + + consumes.checkRequired(this); + } + + @Override + public void load(){ + shadowRegion = Draw.region(shadow == null ? "shadow-" + size : shadow); + region = Draw.region(name); + } + + /** Called when the block is tapped. */ + public void tapped(Tile tile, Player player){ + + } + + /** Returns whether or not a hand cursor should be shown over this block. */ + public CursorType getCursor(Tile tile){ + return configurable ? CursorType.hand : CursorType.normal; + } + + /** + * Called when this block is tapped to build a UI on the table. + * {@link #configurable} able} must return true for this to be called. + */ + public void buildTable(Tile tile, Table table){ + } + + /** + * Called when another tile is tapped while this block is selected. + * Returns whether or not this block should be deselected. + */ + public boolean onConfigureTileTapped(Tile tile, Tile other){ + return tile != other; + } + + /** Returns whether this config menu should show when the specified player taps it. */ + public boolean shouldShowConfigure(Tile tile, Player player){ + return true; + } + + /** Whether this configuration should be hidden now. Called every frame the config is open. */ + public boolean shouldHideConfigure(Tile tile, Player player){ + return false; + } + + public boolean synthetic(){ + return update || destructible || solid; + } + + public void drawConfigure(Tile tile){ + Draw.color(Palette.accent); + Lines.stroke(1f); + Lines.square(tile.drawx(), tile.drawy(), + tile.block().size * tilesize / 2f + 1f); + Draw.reset(); + } + + public void setStats(){ + stats.add(BlockStat.size, "{0}x{0}", size); + stats.add(BlockStat.health, health, StatUnit.none); + + consumes.forEach(cons -> cons.display(stats)); + + if(hasPower) stats.add(BlockStat.powerCapacity, powerCapacity, StatUnit.powerUnits); + if(hasLiquids) stats.add(BlockStat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits); + if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items); + } + + //TODO make this easier to config. + public void setBars(){ + if(hasPower) bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.amount / powerCapacity)); + if(hasLiquids) + bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.total() / liquidCapacity)); + if(hasItems) + bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity)); + } + + public String name(){ + return name; + } + + public boolean isSolidFor(Tile tile){ + return false; + } + + public boolean canReplace(Block other){ + return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group; + } + + public float handleDamage(Tile tile, float amount){ + return amount; + } + + public void handleBulletHit(TileEntity entity, Bullet bullet){ + entity.damage(bullet.getDamage()); + } + + public void update(Tile tile){ + } + + public boolean isAccessible(){ + return (hasItems && itemCapacity > 0); + } + + /** Called after the block is destroyed and removed. */ + public void afterDestroyed(Tile tile, TileEntity entity){ + + } + + /** Called when the block is destroyed. */ + public void onDestroyed(Tile tile){ + float x = tile.worldx(), y = tile.worldy(); + float explosiveness = baseExplosiveness; + float flammability = 0f; + float power = 0f; + int units = 1; + tempColor.set(Palette.darkFlame); + + if(hasItems){ + for(Item item : Item.all()){ + int amount = tile.entity.items.get(item); + explosiveness += item.explosiveness * amount; + flammability += item.flammability * amount; + + if(item.flammability * amount > 0.5){ + units++; + Hue.addu(tempColor, item.flameColor); + } + } + } + + if(hasLiquids){ + flammability += tile.entity.liquids.sum((liquid, amount) -> liquid.explosiveness * amount / 2f); + explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f); + } + + if(hasPower){ + power += tile.entity.power.amount; + } + + tempColor.mul(1f / units); + + if(hasLiquids){ + + tile.entity.liquids.forEach((liquid, amount) -> { + float splash = Mathf.clamp(amount / 4f, 0f, 10f); + + for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){ + Timers.run(i / 2, () -> { + Tile other = world.tile(tile.x + Mathf.range(size / 2), tile.y + Mathf.range(size / 2)); + if(other != null){ + Puddle.deposit(other, liquid, splash); + } + }); + } + }); + } + + Damage.dynamicExplosion(x, y, flammability, explosiveness, power, tilesize * size / 2f, tempColor); + if(!tile.floor().solid && !tile.floor().isLiquid){ + RubbleDecal.create(tile.drawx(), tile.drawy(), size); + } + } + + /** + * Returns the flammability of the tile. Used for fire calculations. + * Takes flammability of floor liquid into account. + */ + public float getFlammability(Tile tile){ + if(!hasItems || tile.entity == null){ + if(tile.floor().isLiquid && !solid){ + return tile.floor().liquidDrop.flammability; + } + return 0; + }else{ + float result = tile.entity.items.sum((item, amount) -> item.flammability * amount); + + if(hasLiquids){ + result += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 3f); + } + + return result; + } + } + + public TextureRegion getEditorIcon(){ + if(editorIcon == null){ + editorIcon = Draw.region("block-icon-" + name, Draw.region("clear")); + } + return editorIcon; + } + + /** Returns the icon used for displaying this block in the place menu */ + public TextureRegion[] getIcon(){ + if(icon == null){ + if(Draw.hasRegion(name + "-icon")){ + icon = new TextureRegion[]{Draw.region(name + "-icon")}; + }else if(Draw.hasRegion(name)){ + icon = new TextureRegion[]{Draw.region(name)}; + }else if(Draw.hasRegion(name + "1")){ + icon = new TextureRegion[]{Draw.region(name + "1")}; + }else{ + icon = new TextureRegion[]{}; + } + } + + return icon; + } + + /** Returns a list of regions that represent this block in the world */ + public TextureRegion[] getBlockIcon(){ + return getIcon(); + } + + /** Returns a list of icon regions that have been cropped to 8x8 */ + public TextureRegion[] getCompactIcon(){ + if(compactIcon == null){ + compactIcon = new TextureRegion[getIcon().length]; + for(int i = 0; i < compactIcon.length; i++){ + compactIcon[i] = iconRegion(getIcon()[i]); + } + } + return compactIcon; + } + + /** Crops a regionto 8x8 */ + protected TextureRegion iconRegion(TextureRegion src){ TextureRegion region = new TextureRegion(src); region.setRegionWidth(8); region.setRegionHeight(8); @@ -403,93 +425,59 @@ public class Block extends BaseBlock implements Content{ } public boolean hasEntity(){ - return destructible || update; - } - - public TileEntity getEntity(){ - return new TileEntity(); - } - - public void draw(Tile tile){ - //note: multiblocks do not support rotation - if(!isMultiblock()){ - Draw.rect(variants > 0 ? (name() + Mathf.randomSeed(tile.id(), 1, variants)) : name(), - tile.worldx(), tile.worldy(), rotate ? tile.getRotation() * 90 : 0); - }else{ - //if multiblock, make sure to draw even block sizes offset, since the core block is at the BOTTOM LEFT - Draw.rect(name(), tile.drawx(), tile.drawy()); - } - - //update the tile entity through the draw method, only if it's an entity without updating - if(destructible && !update && !state.is(State.paused)){ - tile.entity.update(); - } - } + return destructible || update; + } - public void drawNonLayer(Tile tile){} - - public void drawShadow(Tile tile){ - - if(shadowRegions != null) { - Draw.rect(shadowRegions[(Mathf.randomSeed(tile.id(), 0, variants - 1))], tile.worldx(), tile.worldy()); - }else if(shadowRegion != null){ - Draw.rect(shadowRegion, tile.drawx(), tile.drawy()); - } - } - - /**Offset for placing and drawing multiblocks.*/ - public float offset(){ - return ((size + 1) % 2) * tilesize/2; - } - - public boolean isMultiblock(){ - return size > 1; - } + public TileEntity getEntity(){ + return new TileEntity(); + } - public Array getDebugInfo(Tile tile){ - return Array.with( - "block", tile.block().name, - "floor", tile.floor().name, - "x", tile.x, - "y", tile.y, - "entity.name", ClassReflection.getSimpleName(tile.entity.getClass()), - "entity.x", tile.entity.x, - "entity.y", tile.entity.y, - "entity.id", tile.entity.id, - "entity.items.total", hasItems ? tile.entity.items.totalItems() : null - ); - } + public void draw(Tile tile){ + Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0); + } - @Override - public String getContentTypeName() { - return "block"; - } + public void drawNonLayer(Tile tile){ + } - @Override - public Array getAll() { - return all(); - } + public void drawShadow(Tile tile){ + Draw.rect(shadowRegion, tile.drawx(), tile.drawy()); + } - @Override - public String toString(){ - return name; - } + /** Offset for placing and drawing multiblocks. */ + public float offset(){ + return ((size + 1) % 2) * tilesize / 2; + } - public static Array all(){ - return blocks; - } + public boolean isMultiblock(){ + return size > 1; + } - public static Block getByName(String name){ - return map.get(name); - } + public Array getDebugInfo(Tile tile){ + return Array.with( + "block", tile.block().name, + "floor", tile.floor().name, + "x", tile.x, + "y", tile.y, + "entity.name", ClassReflection.getSimpleName(tile.entity.getClass()), + "entity.x", tile.entity.x, + "entity.y", tile.entity.y, + "entity.id", tile.entity.id, + "entity.items.total", hasItems ? tile.entity.items.total() : null + ); + } - public static Block getByID(int id){ - if(id < 0){ //offset negative values by 256, as they are a product of byte overflow - id += 256; - } - if(id >= blocks.size || id < 0){ - throw new RuntimeException("No block with ID '" + id + "' found!"); - } - return blocks.get(id); - } -} + @Override + public String getContentTypeName(){ + return "block"; + } + + @Override + public Array getAll(){ + return all(); + } + + @Override + public String toString(){ + return name; + } +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/world/Build.java b/core/src/io/anuke/mindustry/world/Build.java index aa075581ae..d0fab8e84e 100644 --- a/core/src/io/anuke/mindustry/world/Build.java +++ b/core/src/io/anuke/mindustry/world/Build.java @@ -12,11 +12,13 @@ import io.anuke.ucore.entities.Entities; import static io.anuke.mindustry.Vars.*; -public class Build { +public class Build{ private static final Rectangle rect = new Rectangle(); private static final Rectangle hitrect = new Rectangle(); - /**Returns block type that was broken, or null if unsuccesful.*/ + /** + * Returns block type that was broken, or null if unsuccesful. + */ //@Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks) public static void beginBreak(Team team, int x, int y){ if(!validBreak(team, x, y)){ @@ -38,17 +40,17 @@ public class Build { tile.entity().setDeconstruct(previous); tile.setTeam(team); - if (previous.isMultiblock()) { + if(previous.isMultiblock()){ int offsetx = -(previous.size - 1) / 2; int offsety = -(previous.size - 1) / 2; - for (int dx = 0; dx < previous.size; dx++) { - for (int dy = 0; dy < previous.size; dy++) { + for(int dx = 0; dx < previous.size; dx++){ + for(int dy = 0; dy < previous.size; dy++){ int worldx = dx + offsetx + x; int worldy = dy + offsety + y; - if (!(worldx == x && worldy == y)) { + if(!(worldx == x && worldy == y)){ Tile toplace = world.tile(worldx, worldy); - if (toplace != null) { + if(toplace != null){ toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety)); toplace.setTeam(team); } @@ -59,7 +61,9 @@ public class Build { } - /**Places a BuildBlock at this location.*/ + /** + * Places a BuildBlock at this location. + */ //@Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks) public static void beginPlace(Team team, int x, int y, Recipe recipe, int rotation){ if(!validPlace(team, x, y, recipe.result, rotation)){ @@ -80,17 +84,17 @@ public class Build { tile.entity().setConstruct(previous, recipe); tile.setTeam(team); - if (result.isMultiblock()) { + if(result.isMultiblock()){ int offsetx = -(result.size - 1) / 2; int offsety = -(result.size - 1) / 2; - for (int dx = 0; dx < result.size; dx++) { - for (int dy = 0; dy < result.size; dy++) { + for(int dx = 0; dx < result.size; dx++){ + for(int dy = 0; dy < result.size; dy++){ int worldx = dx + offsetx + x; int worldy = dy + offsety + y; - if (!(worldx == x && worldy == y)) { + if(!(worldx == x && worldy == y)){ Tile toplace = world.tile(worldx, worldy); - if (toplace != null) { + if(toplace != null){ toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety)); toplace.setTeam(team); } @@ -103,35 +107,37 @@ public class Build { threads.runDelay(() -> Events.fire(BlockBuildEvent.class, team, tile)); } - /**Returns whether a tile can be placed at this location by this team.*/ - public static boolean validPlace(Team team, int x, int y, Block type, int rotation) { + /** + * Returns whether a tile can be placed at this location by this team. + */ + public static boolean validPlace(Team team, int x, int y, Block type, int rotation){ Recipe recipe = Recipe.getByResult(type); - if (recipe == null || (recipe.debugOnly && !debug)) { + if(recipe == null || (recipe.debugOnly && !debug)){ return false; } rect.setSize(type.size * tilesize, type.size * tilesize); rect.setCenter(type.offset() + x * tilesize, type.offset() + y * tilesize); - if (type.solid || type.solidifes) { - synchronized (Entities.entityLock) { - try { + if(type.solid || type.solidifes){ + synchronized(Entities.entityLock){ + try{ rect.setSize(tilesize * type.size).setCenter(x * tilesize + type.offset(), y * tilesize + type.offset()); boolean[] result = {false}; Units.getNearby(rect, e -> { - if (e == null) return; //not sure why this happens? + if(e == null) return; //not sure why this happens? e.getHitbox(hitrect); - if (rect.overlaps(hitrect) && !e.isFlying()) { + if(rect.overlaps(hitrect) && !e.isFlying()){ result[0] = true; } }); - if (result[0]) return false; - } catch (Exception e) { + if(result[0]) return false; + }catch(Exception e){ return false; } } @@ -139,10 +145,10 @@ public class Build { Tile tile = world.tile(x, y); - if (tile == null) return false; + if(tile == null) return false; - if (type.isMultiblock()) { - if (type.canReplace(tile.block()) && tile.block().size == type.size) { + if(type.isMultiblock()){ + if(type.canReplace(tile.block()) && tile.block().size == type.size){ return true; } @@ -152,18 +158,18 @@ public class Build { int offsetx = -(type.size - 1) / 2; int offsety = -(type.size - 1) / 2; - for (int dx = 0; dx < type.size; dx++) { - for (int dy = 0; dy < type.size; dy++) { + for(int dx = 0; dx < type.size; dx++){ + for(int dy = 0; dy < type.size; dy++){ Tile other = world.tile(x + dx + offsetx, y + dy + offsety); - if (other == null || (other.block() != Blocks.air && !other.block().alwaysReplace) - || other.cliffs != 0 || !other.floor().placeableOn || - (tile.floor().liquidDrop != null && !type.floating)) { + if(other == null || (other.block() != Blocks.air && !other.block().alwaysReplace) + || other.cliffs != 0 || !other.floor().placeableOn || + (tile.floor().liquidDrop != null && !type.floating)){ return false; } } } return true; - } else { + }else{ return (tile.getTeam() == Team.none || tile.getTeam() == team) && (tile.floor().liquidDrop == null || type.floating) && tile.floor().placeableOn && tile.cliffs == 0 @@ -173,8 +179,10 @@ public class Build { } } - /**Returns whether the tile at this position is breakable by this team*/ - public static boolean validBreak(Team team, int x, int y) { + /** + * Returns whether the tile at this position is breakable by this team + */ + public static boolean validBreak(Team team, int x, int y){ Tile tile = world.tile(x, y); return tile != null && !tile.block().unbreakable diff --git a/core/src/io/anuke/mindustry/world/ColorMapper.java b/core/src/io/anuke/mindustry/world/ColorMapper.java index 74b20c6308..012caefe05 100644 --- a/core/src/io/anuke/mindustry/world/ColorMapper.java +++ b/core/src/io/anuke/mindustry/world/ColorMapper.java @@ -8,30 +8,30 @@ import io.anuke.mindustry.game.Content; import io.anuke.mindustry.type.ContentList; public class ColorMapper implements ContentList{ - private static IntMap blockMap = new IntMap<>(); - private static ObjectIntMap colorMap = new ObjectIntMap<>(); + private static IntMap blockMap = new IntMap<>(); + private static ObjectIntMap colorMap = new ObjectIntMap<>(); - @Override - public void load() { - for(Block block : Block.all()){ - int color = Color.rgba8888(block.minimapColor); - if(color == 0) continue; //skip blocks that are not mapped + public static Block getByColor(int color){ + return blockMap.get(color); + } - blockMap.put(color, block); - colorMap.put(block, color); - } - } + public static int getBlockColor(Block block){ + return colorMap.get(block, 0); + } - @Override - public Array getAll() { - return new Array<>(); - } + @Override + public void load(){ + for(Block block : Block.all()){ + int color = Color.rgba8888(block.minimapColor); + if(color == 0) continue; //skip blocks that are not mapped - public static Block getByColor(int color){ - return blockMap.get(color); - } + blockMap.put(color, block); + colorMap.put(block, color); + } + } - public static int getBlockColor(Block block){ - return colorMap.get(block, 0); - } + @Override + public Array getAll(){ + return new Array<>(); + } } diff --git a/core/src/io/anuke/mindustry/world/Edges.java b/core/src/io/anuke/mindustry/world/Edges.java index 61575ba381..8565b5a50d 100644 --- a/core/src/io/anuke/mindustry/world/Edges.java +++ b/core/src/io/anuke/mindustry/world/Edges.java @@ -7,51 +7,61 @@ import io.anuke.ucore.util.Mathf; import java.util.Arrays; -public class Edges { +import static io.anuke.mindustry.Vars.world; + +public class Edges{ private static final int maxSize = 11; private static final int maxRadius = 12; private static GridPoint2[][] edges = new GridPoint2[maxSize][0]; private static GridPoint2[][] edgeInside = new GridPoint2[maxSize][0]; - private static Vector2[][] polygons = new Vector2[maxRadius*2][0]; + private static Vector2[][] polygons = new Vector2[maxRadius * 2][0]; static{ - for(int i = 0; i < maxRadius*2; i ++){ - polygons[i] = Geometry.pixelCircle((i + 1)/2f); + for(int i = 0; i < maxRadius * 2; i++){ + polygons[i] = Geometry.pixelCircle((i + 1) / 2f); } - for(int i = 0; i < maxSize; i ++){ - int bot = -(int)(i/2f) - 1; - int top = (int)(i/2f+0.5f) + 1; + for(int i = 0; i < maxSize; i++){ + int bot = -(int) (i / 2f) - 1; + int top = (int) (i / 2f + 0.5f) + 1; edges[i] = new GridPoint2[(i + 1) * 4]; int idx = 0; - for(int j = 0; j < i + 1; j ++){ + for(int j = 0; j < i + 1; j++){ //bottom - edges[i][idx ++] = new GridPoint2(bot + 1 + j, bot); + edges[i][idx++] = new GridPoint2(bot + 1 + j, bot); //top - edges[i][idx ++] = new GridPoint2(bot + 1 + j, top); + edges[i][idx++] = new GridPoint2(bot + 1 + j, top); //left - edges[i][idx ++] = new GridPoint2(bot, bot + j + 1); + edges[i][idx++] = new GridPoint2(bot, bot + j + 1); //right - edges[i][idx ++] = new GridPoint2(top, bot + j + 1); + edges[i][idx++] = new GridPoint2(top, bot + j + 1); } Arrays.sort(edges[i], (e1, e2) -> Float.compare(Mathf.atan2(e1.x, e1.y), Mathf.atan2(e2.x, e2.y))); edgeInside[i] = new GridPoint2[edges[i].length]; - for(int j = 0; j < edges[i].length; j ++){ + for(int j = 0; j < edges[i].length; j++){ GridPoint2 point = edges[i][j]; - edgeInside[i][j] = new GridPoint2(Mathf.clamp(point.x, -(int)((i)/2f), (int)(i/2f + 0.5f)), - Mathf.clamp(point.y, -(int)((i)/2f), (int)(i/2f + 0.5f))); + edgeInside[i][j] = new GridPoint2(Mathf.clamp(point.x, -(int) ((i) / 2f), (int) (i / 2f + 0.5f)), + Mathf.clamp(point.y, -(int) ((i) / 2f), (int) (i / 2f + 0.5f))); } } } + public static Tile getFacingEdge(Tile tile, Tile other){ + if(!tile.block().isMultiblock()) return tile; + int size = tile.block().size; + return world.tile(tile.x + Mathf.clamp(other.x - tile.x, -(size - 1) / 2, (size / 2)), + tile.y + Mathf.clamp(other.y - tile.y, -(size - 1) / 2, (size / 2))); + } + public static Vector2[] getPixelPolygon(float radius){ - if(radius < 1 || radius > maxRadius) throw new RuntimeException("Polygon size must be between 1 and " + maxRadius); - return polygons[(int)(radius*2) - 1]; + if(radius < 1 || radius > maxRadius) + throw new RuntimeException("Polygon size must be between 1 and " + maxRadius); + return polygons[(int) (radius * 2) - 1]; } public static synchronized GridPoint2[] getEdges(int size){ diff --git a/core/src/io/anuke/mindustry/world/ItemBuffer.java b/core/src/io/anuke/mindustry/world/ItemBuffer.java index fa0ba89eb5..d3ba23f394 100644 --- a/core/src/io/anuke/mindustry/world/ItemBuffer.java +++ b/core/src/io/anuke/mindustry/world/ItemBuffer.java @@ -5,7 +5,7 @@ import io.anuke.mindustry.type.Item; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Bits; -public class ItemBuffer { +public class ItemBuffer{ private final float speed; private long[] buffer; @@ -20,9 +20,13 @@ public class ItemBuffer { return index < buffer.length; } - public void accept(Item item){ + public void accept(Item item, short data){ //if(!accepts()) return; - buffer[index ++] = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), item.id); + buffer[index++] = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), Bits.packInt((short) item.id, data)); + } + + public void accept(Item item){ + accept(item, (short) -1); } public Item poll(){ @@ -31,14 +35,26 @@ public class ItemBuffer { float time = NumberUtils.intBitsToFloat(Bits.getLeftInt(l)); if(Timers.time() >= time + speed || Timers.time() < time){ - return Item.getByID(Bits.getRightInt(l)); + return Item.getByID(Bits.getLeftShort(Bits.getRightInt(l))); } } return null; } + public short pollData(){ + if(index > 0){ + long l = buffer[0]; + float time = NumberUtils.intBitsToFloat(Bits.getLeftInt(l)); + + if(Timers.time() >= time + speed || Timers.time() < time){ + return Bits.getRightShort(Bits.getRightInt(l)); + } + } + return -1; + } + public void remove(){ System.arraycopy(buffer, 1, buffer, 0, index - 1); - index --; + index--; } } diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index 3f60494762..4ea601b896 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -10,9 +10,10 @@ import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.blocks.Floor; -import io.anuke.mindustry.world.blocks.modules.InventoryModule; -import io.anuke.mindustry.world.blocks.modules.LiquidModule; -import io.anuke.mindustry.world.blocks.modules.PowerModule; +import io.anuke.mindustry.world.modules.ConsumeModule; +import io.anuke.mindustry.world.modules.InventoryModule; +import io.anuke.mindustry.world.modules.LiquidModule; +import io.anuke.mindustry.world.modules.PowerModule; import io.anuke.ucore.entities.trait.PosTrait; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.util.Bits; @@ -23,420 +24,426 @@ import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class Tile implements PosTrait, TargetTrait { - public static final Object tileSetLock = new Object(); - - /**Block ID data.*/ - private Block wall; - private Floor floor; - /**Rotation, 0-3. Also used to store offload location for routers, in which case it can be any number.*/ - private byte rotation; - /**Team ordinal.*/ - private byte team; - /**The coordinates of the core tile this is linked to, in the form of two bytes packed into one. - * This is relative to the block it is linked to; negate coords to find the link.*/ - public byte link = 0; - public short x, y; - /**Tile traversal cost.*/ - public byte cost = 1; - /**Elevation of tile.*/ - public byte elevation; - /**Position of cliffs around the tile, packed into bits 0-8.*/ - public byte cliffs; - /**Tile entity, usually null.*/ - public TileEntity entity; - - public Tile(int x, int y){ - this.x = (short)x; - this.y = (short)y; - } +public class Tile implements PosTrait, TargetTrait{ + public static final Object tileSetLock = new Object(); + /** + * The coordinates of the core tile this is linked to, in the form of two bytes packed into one. + * This is relative to the block it is linked to; negate coords to find the link. + */ + public byte link = 0; + public short x, y; + /** Tile traversal cost. */ + public byte cost = 1; + /** Elevation of tile. */ + public byte elevation; + /** Position of cliffs around the tile, packed into bits 0-8. */ + public byte cliffs; + /** Tile entity, usually null. */ + public TileEntity entity; + /** Block ID data. */ + private Block wall; + private Floor floor; + /** Rotation, 0-3. Also used to store offload location for routers, in which case it can be any number. */ + private byte rotation; + /** Team ordinal. */ + private byte team; - public Tile(int x, int y, byte floor, byte wall){ - this(x, y); - this.floor = (Floor) Block.getByID(floor); - this.wall = Block.getByID(wall); - changed(); - } - - public Tile(int x, int y, byte floor, byte wall, byte rotation, byte team, byte elevation){ - this(x, y); - this.floor =(Floor) Block.getByID(floor); - this.wall = Block.getByID(wall); - this.rotation = rotation; - this.elevation = elevation; - changed(); - this.team = team; - } + public Tile(int x, int y){ + this.x = (short) x; + this.y = (short) y; + } - public int packedPosition(){ - return x + y * world.width(); - } - - public byte getWallID(){ - return (byte)wall.id; - } - - public byte getFloorID(){ - return (byte)floor.id; - } - - /**Return relative rotation to a coordinate. Returns -1 if the coordinate is not near this tile.*/ - public byte relativeTo(int cx, int cy){ - if(x == cx && y == cy - 1) return 1; - if(x == cx && y == cy + 1) return 3; - if(x == cx - 1 && y == cy) return 0; - if(x == cx + 1 && y == cy) return 2; - return -1; - } + public Tile(int x, int y, byte floor, byte wall){ + this(x, y); + this.floor = (Floor) Block.getByID(floor); + this.wall = Block.getByID(wall); + changed(); + } - public byte absoluteRelativeTo(int cx, int cy){ - if(x == cx && y <= cy - 1) return 1; - if(x == cx && y >= cy + 1) return 3; - if(x <= cx - 1 && y == cy) return 0; - if(x >= cx + 1 && y == cy) return 2; - return -1; - } + public Tile(int x, int y, byte floor, byte wall, byte rotation, byte team, byte elevation){ + this(x, y); + this.floor = (Floor) Block.getByID(floor); + this.wall = Block.getByID(wall); + this.rotation = rotation; + this.elevation = elevation; + changed(); + this.team = team; + } - public byte sizedRelativeTo(int cx, int cy){ - if(x == cx && y == cy - 1 - block().size/2) return 1; - if(x == cx && y == cy + 1 + block().size/2) return 3; - if(x == cx - 1 - block().size/2 && y == cy) return 0; - if(x == cx + 1 + block().size/2 && y == cy) return 2; - return -1; - } - - public T entity(){ - return (T)entity; - } - - public int id(){ - return x + y * world.width(); - } - - public float worldx(){ - return x * tilesize; - } - - public float worldy(){ - return y * tilesize; - } + public int packedPosition(){ + return x + y * world.width(); + } - public float drawx(){ - return block().offset() + worldx(); - } + public byte getWallID(){ + return (byte) wall.id; + } - public float drawy(){ - return block().offset() + worldy(); - } - - public Floor floor(){ - return floor; - } - - public Block block(){ - return wall; - } + public byte getFloorID(){ + return (byte) floor.id; + } - public Team getTeam(){ - return Team.all[team]; - } + /** Return relative rotation to a coordinate. Returns -1 if the coordinate is not near this tile. */ + public byte relativeTo(int cx, int cy){ + if(x == cx && y == cy - 1) return 1; + if(x == cx && y == cy + 1) return 3; + if(x == cx - 1 && y == cy) return 0; + if(x == cx + 1 && y == cy) return 2; + return -1; + } - public byte getTeamID(){ - return team; - } + public byte absoluteRelativeTo(int cx, int cy){ + if(x == cx && y <= cy - 1) return 1; + if(x == cx && y >= cy + 1) return 3; + if(x <= cx - 1 && y == cy) return 0; + if(x >= cx + 1 && y == cy) return 2; + return -1; + } - public void setTeam(Team team){ - this.team = (byte)team.ordinal(); - } - - /**Returns the break time of the block, or the breaktime of the linked block, if this tile is linked.*/ - public float getBreakTime(){ - Block block = target().block(); - if(Recipe.getByResult(block) != null){ - return Recipe.getByResult(block).cost; - }else{ - return 15f; - } - } - - public void setBlock(Block type, int rotation){ - synchronized (tileSetLock) { - if(rotation < 0) rotation = (-rotation + 2); - this.wall = type; - this.link = 0; - setRotation((byte) (rotation % 4)); - changed(); - } - } - - public void setBlock(Block type){ - synchronized (tileSetLock) { - this.wall = type; - this.link = 0; - changed(); - } - } - - public void setFloor(Floor type){ - this.floor = type; - } - - public void setRotation(byte rotation){ - this.rotation = rotation; - } - - public void setDump(byte dump){ - this.rotation = dump; - } - - public byte getRotation(){ - return rotation; - } - - public byte getDump(){ - return rotation; - } + public byte sizedRelativeTo(int cx, int cy){ + if(x == cx && y == cy - 1 - block().size / 2) return 1; + if(x == cx && y == cy + 1 + block().size / 2) return 3; + if(x == cx - 1 - block().size / 2 && y == cy) return 0; + if(x == cx + 1 + block().size / 2 && y == cy) return 2; + return -1; + } - public boolean passable(){ - Block block = block(); - Block floor = floor(); - return isLinked() || !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update))); - } + public T entity(){ + return (T) entity; + } - /**Whether this block was placed by a player/unit.*/ - public boolean synthetic(){ - Block block = block(); - return block.update || block.destructible; - } - - public boolean solid(){ - Block block = block(); - Block floor = floor(); - return block.solid || cliffs != 0 || (floor.solid && (block == Blocks.air || block.solidifes)) || block.isSolidFor(this) - || (isLinked() && getLinked().block().isSolidFor(getLinked())); - } - - public boolean breakable(){ - Block block = block(); - if(link == 0){ - return (block.destructible || block.breakable || block.update); - }else{ - return getLinked().breakable(); - } - } - - public boolean isLinked(){ - return link != 0; - } - - /**Sets this to a linked tile, which sets the block to a blockpart. dx and dy can only be -8-7.*/ - public void setLinked(byte dx, byte dy){ - setBlock(Blocks.blockpart); - link = Bits.packByte((byte)(dx + 8), (byte)(dy + 8)); - } - - /**Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock. - * This array contains all linked tiles, including this tile itself.*/ - public synchronized Array getLinkedTiles(Array tmpArray){ - Block block = block(); - tmpArray.clear(); - if(block.isMultiblock()){ - int offsetx = -(block.size-1)/2; - int offsety = -(block.size-1)/2; - for(int dx = 0; dx < block.size; dx ++){ - for(int dy = 0; dy < block.size; dy ++){ - Tile other = world.tile(x + dx + offsetx, y + dy + offsety); - tmpArray.add(other); - } - } - }else{ - tmpArray.add(this); - } - return tmpArray; - } + public int id(){ + return x + y * world.width(); + } - /**Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock. - * This array contains all linked tiles, including this tile itself.*/ - public synchronized Array getLinkedTilesAs(Block block, Array tmpArray){ - tmpArray.clear(); - if(block.isMultiblock()){ - int offsetx = -(block.size-1)/2; - int offsety = -(block.size-1)/2; - for(int dx = 0; dx < block.size; dx ++){ - for(int dy = 0; dy < block.size; dy ++){ - Tile other = world.tile(x + dx + offsetx, y + dy + offsety); - tmpArray.add(other); - } - } - }else{ - tmpArray.add(this); - } - return tmpArray; - } - - /**Returns the block the multiblock is linked to, or null if it is not linked to any block.*/ - public Tile getLinked(){ - if(link == 0){ - return null; - }else{ - byte dx = Bits.getLeftByte(link); - byte dy = Bits.getRightByte(link); - return world.tile(x - (dx - 8), y - (dy - 8)); - } - } + public float worldx(){ + return x * tilesize; + } - public void allNearby(Consumer cons){ - for(GridPoint2 point : Edges.getEdges(block().size)){ - Tile tile = world.tile(x + point.x, y + point.y); - if(tile != null){ - cons.accept(tile.target()); - } - } - } + public float worldy(){ + return y * tilesize; + } - public void allInside(Consumer cons){ - for(GridPoint2 point : Edges.getInsideEdges(block().size)){ - Tile tile = world.tile(x + point.x, y + point.y); - if(tile != null){ - cons.accept(tile); - } - } - } + public float drawx(){ + return block().offset() + worldx(); + } - public Tile target(){ - Tile link = getLinked(); - return link == null ? this : link; - } + public float drawy(){ + return block().offset() + worldy(); + } - public Tile getNearby(GridPoint2 relative){ - return world.tile(x + relative.x, y + relative.y); - } + public Floor floor(){ + return floor; + } - public Tile getNearby(int dx, int dy){ - return world.tile(x + dx, y + dy); - } + public Block block(){ + return wall; + } - public Tile getNearby(int rotation){ - if(rotation == 0) return world.tile(x + 1, y); - if(rotation == 1) return world.tile(x, y + 1); - if(rotation == 2) return world.tile(x - 1, y); - if(rotation == 3) return world.tile(x, y - 1); - return null; - } + public Team getTeam(){ + return Team.all[team]; + } - public Tile[] getNearby(Tile[] temptiles){ - temptiles[0] = world.tile(x+1, y); - temptiles[1] = world.tile(x, y+1); - temptiles[2] = world.tile(x-1, y); - temptiles[3] = world.tile(x, y-1); - return temptiles; - } + public void setTeam(Team team){ + this.team = (byte) team.ordinal(); + } - public void updateOcclusion(){ - cost = 1; - cliffs = 0; - boolean occluded = false; + public byte getTeamID(){ + return team; + } - //check for occlusion - for(int i = 0; i < 8; i ++){ - GridPoint2 point = Geometry.d8[i]; - Tile tile = world.tile(x + point.x, y + point.y); - if(tile != null && tile.solid()){ - occluded = true; - break; - } - } + /** Returns the break time of the block, or the breaktime of the linked block, if this tile is linked. */ + public float getBreakTime(){ + Block block = target().block(); + if(Recipe.getByResult(block) != null){ + return Recipe.getByResult(block).cost; + }else{ + return 15f; + } + } - //check for bitmasking cliffs - for(int i = 0; i < 4; i ++){ - GridPoint2 pc = Geometry.d4[i]; - GridPoint2 pcprev = Geometry.d4[Mathf.mod(i - 1, 4)]; - GridPoint2 pcnext = Geometry.d4[(i + 1) % 4]; - GridPoint2 pe = Geometry.d8edge[i]; + public void setBlock(Block type, int rotation){ + synchronized(tileSetLock){ + preChanged(); + if(rotation < 0) rotation = (-rotation + 2); + this.wall = type; + this.link = 0; + setRotation((byte) (rotation % 4)); + changed(); + } + } - Tile tc = world.tile(x + pc.x, y + pc.y); - Tile tprev = world.tile(x + pcprev.x, y + pcprev.y); - Tile tnext = world.tile(x + pcnext.x, y + pcnext.y); - Tile te = world.tile(x + pe.x, y + pe.y); - Tile tex = world.tile(x, y + pe.y); - Tile tey = world.tile(x + pe.x, y); + public void setBlock(Block type){ + synchronized(tileSetLock){ + preChanged(); + this.wall = type; + this.link = 0; + changed(); + } + } - //check for cardinal direction elevation changes and bitmask that - if(tc != null && tprev != null && tnext != null && ((tc.elevation < elevation && tc.elevation != -1))){ - cliffs |= (1 << (i*2)); - } + public void setFloor(Floor type){ + this.floor = type; + } - //00S - //0X0 - //010 + public byte getRotation(){ + return rotation; + } - //check for corner bitmasking: doesn't even get checked so it doesn't matter - /*if(te != null && tex != null && tey != null && te.elevation == -1 && elevation > 0){ - cliffs |= (1 << (((i+1)%4)*2)); - }*/ - } - if(occluded){ - cost += 1; - } - } - - public void changed(){ + public void setRotation(byte rotation){ + this.rotation = rotation; + } - synchronized (tileSetLock) { - if (entity != null) { - entity.remove(); - entity = null; - } + public byte getDump(){ + return rotation; + } - team = 0; + public void setDump(byte dump){ + this.rotation = dump; + } - Block block = block(); + public boolean passable(){ + Block block = block(); + Block floor = floor(); + return isLinked() || !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update))); + } - if (block.hasEntity()) { - entity = block.getEntity().init(this, block.update); - if(block.hasItems) entity.items = new InventoryModule(); - if(block.hasLiquids) entity.liquids = new LiquidModule(); - if(block.hasPower) entity.power = new PowerModule(); - } + /** Whether this block was placed by a player/unit. */ + public boolean synthetic(){ + Block block = block(); + return block.update || block.destructible; + } - updateOcclusion(); - } + public boolean solid(){ + Block block = block(); + Block floor = floor(); + return block.solid || cliffs != 0 || (floor.solid && (block == Blocks.air || block.solidifes)) || block.isSolidFor(this) + || (isLinked() && getLinked().block().isSolidFor(getLinked())); + } - world.notifyChanged(this); - } + public boolean breakable(){ + Block block = block(); + if(link == 0){ + return (block.destructible || block.breakable || block.update); + }else{ + return getLinked().breakable(); + } + } - @Override - public boolean isDead() { - return false; //tiles never die - } + public boolean isLinked(){ + return link != 0; + } - @Override - public Vector2 getVelocity() { - return Vector2.Zero; - } + /** Sets this to a linked tile, which sets the block to a blockpart. dx and dy can only be -8-7. */ + public void setLinked(byte dx, byte dy){ + setBlock(Blocks.blockpart); + link = Bits.packByte((byte) (dx + 8), (byte) (dy + 8)); + } - @Override - public float getX() { - return drawx(); - } + /** + * Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock. + * This array contains all linked tiles, including this tile itself. + */ + public synchronized Array getLinkedTiles(Array tmpArray){ + Block block = block(); + tmpArray.clear(); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + Tile other = world.tile(x + dx + offsetx, y + dy + offsety); + tmpArray.add(other); + } + } + }else{ + tmpArray.add(this); + } + return tmpArray; + } - @Override - public float getY() { - return drawy(); - } + /** + * Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock. + * This array contains all linked tiles, including this tile itself. + */ + public synchronized Array getLinkedTilesAs(Block block, Array tmpArray){ + tmpArray.clear(); + if(block.isMultiblock()){ + int offsetx = -(block.size - 1) / 2; + int offsety = -(block.size - 1) / 2; + for(int dx = 0; dx < block.size; dx++){ + for(int dy = 0; dy < block.size; dy++){ + Tile other = world.tile(x + dx + offsetx, y + dy + offsety); + tmpArray.add(other); + } + } + }else{ + tmpArray.add(this); + } + return tmpArray; + } - @Override - public void setX(float x) {} + /** Returns the block the multiblock is linked to, or null if it is not linked to any block. */ + public Tile getLinked(){ + if(link == 0){ + return null; + }else{ + byte dx = Bits.getLeftByte(link); + byte dy = Bits.getRightByte(link); + return world.tile(x - (dx - 8), y - (dy - 8)); + } + } - @Override - public void setY(float y) {} + public void allNearby(Consumer cons){ + for(GridPoint2 point : Edges.getEdges(block().size)){ + Tile tile = world.tile(x + point.x, y + point.y); + if(tile != null){ + cons.accept(tile.target()); + } + } + } - @Override - public String toString(){ - Block block = block(); - Block floor = floor(); - - return floor.name() + ":" + block.name() + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : ClassReflection.getSimpleName(entity.getClass())) + - (link != 0 ? " link=[" + (Bits.getLeftByte(link) - 8) + ", " + (Bits.getRightByte(link) - 8) + "]" : ""); - } -} + public void allInside(Consumer cons){ + for(GridPoint2 point : Edges.getInsideEdges(block().size)){ + Tile tile = world.tile(x + point.x, y + point.y); + if(tile != null){ + cons.accept(tile); + } + } + } + + public Tile target(){ + Tile link = getLinked(); + return link == null ? this : link; + } + + public Tile getNearby(GridPoint2 relative){ + return world.tile(x + relative.x, y + relative.y); + } + + public Tile getNearby(int dx, int dy){ + return world.tile(x + dx, y + dy); + } + + public Tile getNearby(int rotation){ + if(rotation == 0) return world.tile(x + 1, y); + if(rotation == 1) return world.tile(x, y + 1); + if(rotation == 2) return world.tile(x - 1, y); + if(rotation == 3) return world.tile(x, y - 1); + return null; + } + + public Tile[] getNearby(Tile[] temptiles){ + temptiles[0] = world.tile(x + 1, y); + temptiles[1] = world.tile(x, y + 1); + temptiles[2] = world.tile(x - 1, y); + temptiles[3] = world.tile(x, y - 1); + return temptiles; + } + + public void updateOcclusion(){ + cost = 1; + cliffs = 0; + boolean occluded = false; + + //check for occlusion + for(int i = 0; i < 8; i++){ + GridPoint2 point = Geometry.d8[i]; + Tile tile = world.tile(x + point.x, y + point.y); + if(tile != null && tile.solid()){ + occluded = true; + break; + } + } + + //check for bitmasking cliffs + for(int i = 0; i < 4; i++){ + GridPoint2 pc = Geometry.d4[i]; + GridPoint2 pcprev = Geometry.d4[Mathf.mod(i - 1, 4)]; + GridPoint2 pcnext = Geometry.d4[(i + 1) % 4]; + + Tile tc = world.tile(x + pc.x, y + pc.y); + Tile tprev = world.tile(x + pcprev.x, y + pcprev.y); + Tile tnext = world.tile(x + pcnext.x, y + pcnext.y); + + //check for cardinal direction elevation changes and bitmask that + if(tc != null && tprev != null && tnext != null && ((tc.elevation < elevation && tc.elevation != -1))){ + cliffs |= (1 << (i * 2)); + } + } + if(occluded){ + cost += 1; + } + } + + private void preChanged(){ + synchronized(tileSetLock){ + if(entity != null){ + entity.removeFromProximity(); + } + } + } + + private void changed(){ + + synchronized(tileSetLock){ + if(entity != null){ + entity.remove(); + entity = null; + } + + team = 0; + + Block block = block(); + + if(block.hasEntity()){ + entity = block.getEntity().init(this, block.update); + entity.cons = new ConsumeModule(); + if(block.hasItems) entity.items = new InventoryModule(); + if(block.hasLiquids) entity.liquids = new LiquidModule(); + if(block.hasPower) entity.power = new PowerModule(); + entity.updateProximity(); + } + + updateOcclusion(); + } + + world.notifyChanged(this); + } + + @Override + public boolean isDead(){ + return false; //tiles never die + } + + @Override + public Vector2 getVelocity(){ + return Vector2.Zero; + } + + @Override + public float getX(){ + return drawx(); + } + + @Override + public void setX(float x){ + } + + @Override + public float getY(){ + return drawy(); + } + + @Override + public void setY(float y){ + } + + @Override + public String toString(){ + Block block = block(); + Block floor = floor(); + + return floor.name() + ":" + block.name() + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : ClassReflection.getSimpleName(entity.getClass())) + + (link != 0 ? " link=[" + (Bits.getLeftByte(link) - 8) + ", " + (Bits.getRightByte(link) - 8) + "]" : ""); + } +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/world/blocks/BlendBlock.java b/core/src/io/anuke/mindustry/world/blocks/BlendBlock.java deleted file mode 100644 index 7c01a052be..0000000000 --- a/core/src/io/anuke/mindustry/world/blocks/BlendBlock.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.anuke.mindustry.world.blocks; - -import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.function.Predicate; -import io.anuke.ucore.util.Mathf; - -public class BlendBlock extends Block{ - protected String edge; - protected Predicate blend = block -> block == this; - - public BlendBlock(String name) { - super(name); - edge = name + "-edge"; - } - - @Override - public void draw(Tile tile){ - Draw.rect(variants > 0 ? (name() + Mathf.randomSeed(tile.id(), 1, variants)) : name(), - tile.worldx(), tile.worldy()); - - for(int i = 0; i < 4; i ++){ - Tile near = tile.getNearby(i); - if(near != null && !blend.test(near.block())){ - Draw.rect(edge + "-" + i, tile.worldx(), tile.worldy()); - } - } - } -} diff --git a/core/src/io/anuke/mindustry/world/blocks/BlockPart.java b/core/src/io/anuke/mindustry/world/blocks/BlockPart.java index 37788c5f23..dd90451dec 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BlockPart.java +++ b/core/src/io/anuke/mindustry/world/blocks/BlockPart.java @@ -5,75 +5,77 @@ import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -/**Used for multiblocks. Each block that is not the center of the multiblock is a blockpart. +/** + * Used for multiblocks. Each block that is not the center of the multiblock is a blockpart. * Think of these as delegates to the actual block; all events are passed to the target block. - * They are made to share all properties from the linked tile/block.*/ + * They are made to share all properties from the linked tile/block. + */ public class BlockPart extends Block{ - public BlockPart() { - super("blockpart"); - solid = false; - hasPower = hasItems = hasLiquids = true; - } - - @Override - public void draw(Tile tile){ - //do nothing - } + public BlockPart(){ + super("blockpart"); + solid = false; + hasPower = hasItems = hasLiquids = true; + } - @Override - public void drawShadow(Tile tile){ - //also do nothing - } - - @Override - public boolean isSolidFor(Tile tile){ - return tile.getLinked() == null - || (tile.getLinked().block() instanceof BlockPart || tile.getLinked().solid() - || tile.getLinked().block().isSolidFor(tile.getLinked())); - } - - @Override - public void handleItem(Item item, Tile tile, Tile source){ - tile.getLinked().block().handleItem(item, tile.getLinked(), source); - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - return tile.getLinked().block().acceptItem(item, tile.getLinked(), source); - } + @Override + public void draw(Tile tile){ + //do nothing + } - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - Block block = linked(tile); - return block.hasLiquids - && block.acceptLiquid(tile.getLinked(), source, liquid, amount); - } + @Override + public void drawShadow(Tile tile){ + //also do nothing + } - @Override - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - Block block = linked(tile); - block.handleLiquid(tile.getLinked(), source, liquid, amount); - } + @Override + public boolean isSolidFor(Tile tile){ + return tile.getLinked() == null + || (tile.getLinked().block() instanceof BlockPart || tile.getLinked().solid() + || tile.getLinked().block().isSolidFor(tile.getLinked())); + } - @Override - public float addPower(Tile tile, float amount){ - Block block = linked(tile); - if(block.hasPower){ - return block.addPower(tile.getLinked(), amount); - }else{ - return amount; - } - } - - @Override - public boolean acceptPower(Tile tile, Tile from, float amount) { + @Override + public void handleItem(Item item, Tile tile, Tile source){ + tile.getLinked().block().handleItem(item, tile.getLinked(), source); + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + return tile.getLinked().block().acceptItem(item, tile.getLinked(), source); + } + + @Override + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + Block block = linked(tile); + return block.hasLiquids + && block.acceptLiquid(tile.getLinked(), source, liquid, amount); + } + + @Override + public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + Block block = linked(tile); + block.handleLiquid(tile.getLinked(), source, liquid, amount); + } + + @Override + public float addPower(Tile tile, float amount){ + Block block = linked(tile); + if(block.hasPower){ + return block.addPower(tile.getLinked(), amount); + }else{ + return amount; + } + } + + @Override + public boolean acceptPower(Tile tile, Tile from, float amount){ Block block = linked(tile); return block.hasPower && block.acceptPower(tile.getLinked(), from, amount); } - - private Block linked(Tile tile){ - return tile.getLinked().block(); - } + + private Block linked(Tile tile){ + return tile.getLinked().block(); + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 31979b1aed..6456b886ad 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -22,8 +22,8 @@ import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.blocks.modules.InventoryModule; import io.anuke.mindustry.world.meta.BlockBar; +import io.anuke.mindustry.world.modules.InventoryModule; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Graphics; import io.anuke.ucore.graphics.Draw; @@ -35,30 +35,51 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class BuildBlock extends Block { - public BuildBlock(String name) { +public class BuildBlock extends Block{ + public BuildBlock(String name){ super(name); update = true; - size = Integer.parseInt(name.charAt(name.length()-1) + ""); + size = Integer.parseInt(name.charAt(name.length() - 1) + ""); health = 1; layer = Layer.placement; consumesTap = true; solidifes = true; } + @Remote(called = Loc.server, in = In.blocks) + public static void onDeconstructFinish(Tile tile, Block block){ + Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size); + world.removeBlock(tile); + } + + @Remote(called = Loc.server, in = In.blocks) + public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team){ + world.setBlock(tile, block, team); + tile.setRotation(rotation); + tile.setTeam(team); + Effects.effect(Fx.placeBlock, tile.drawx(), tile.drawy(), block.size); + + //last builder was this local client player, call placed() + if(!headless && builderID == players[0].id){ + //this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish() + //event first before they can recieve the placed() event modification results + threads.runDelay(() -> tile.block().placed(tile)); + } + } + @Override - public boolean isSolidFor(Tile tile) { + public boolean isSolidFor(Tile tile){ BuildEntity entity = tile.entity(); return entity == null || entity.recipe == null || entity.recipe.result.solid || entity.previous.solid; } @Override - public CursorType getCursor(Tile tile) { + public CursorType getCursor(Tile tile){ return CursorType.hand; } @Override - public void tapped(Tile tile, Player player) { + public void tapped(Tile tile, Player player){ BuildEntity entity = tile.entity(); //if the target is constructible, begin constructing @@ -70,7 +91,7 @@ public class BuildBlock extends Block { @Override public void setBars(){ - bars.replace(new BlockBar(BarType.health, true, tile -> (float)tile.entity().progress)); + bars.replace(new BlockBar(BarType.health, true, tile -> tile.entity().progress)); } @Override @@ -84,7 +105,7 @@ public class BuildBlock extends Block { @Override public void afterDestroyed(Tile tile, TileEntity e){ - BuildEntity entity = (BuildEntity)e; + BuildEntity entity = (BuildEntity) e; if(entity.previous != null && entity.previous.synthetic()){ tile.setBlock(entity.previous); @@ -100,13 +121,16 @@ public class BuildBlock extends Block { return; } - for (TextureRegion region : entity.previous.getBlockIcon()) { + if(entity.previous == null) return; + + for(TextureRegion region : entity.previous.getBlockIcon()){ Draw.rect(region, tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.getRotation() * 90 : 0); } } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ + BuildEntity entity = tile.entity(); Shaders.blockbuild.color = Palette.accent; @@ -117,7 +141,7 @@ public class BuildBlock extends Block { for(TextureRegion region : target.getBlockIcon()){ Shaders.blockbuild.region = region; - Shaders.blockbuild.progress = (float)entity.progress; + Shaders.blockbuild.progress = (float) entity.progress; Shaders.blockbuild.apply(); Draw.rect(region, tile.drawx(), tile.drawy(), target.rotate ? tile.getRotation() * 90 : 0); @@ -127,93 +151,80 @@ public class BuildBlock extends Block { } @Override - public void drawShadow(Tile tile) { + public void drawShadow(Tile tile){ BuildEntity entity = tile.entity(); - if(entity.recipe != null){ - entity.recipe.result.drawShadow(tile); - }else if(entity.previous != null){ - entity.previous.drawShadow(tile); + Recipe recipe = entity.recipe; + Block previous = entity.previous; + + if(recipe != null){ + recipe.result.drawShadow(tile); + }else if(previous != null){ + previous.drawShadow(tile); } } @Override - public void update(Tile tile) { + public void update(Tile tile){ } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new BuildEntity(); } - @Remote(called = Loc.server, in = In.blocks) - public static void onDeconstructFinish(Tile tile, Block block){ - Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size); - world.removeBlock(tile); - } - - @Remote(called = Loc.server, in = In.blocks) - public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation){ - Team team = tile.getTeam(); - tile.setBlock(block); - tile.setTeam(team); - tile.setRotation(rotation); - Effects.effect(Fx.placeBlock, tile.drawx(), tile.drawy(), block.size); - - //last builder was this local client player, call placed() - if(!headless && builderID == players[0].id){ - //this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish() - //event first before they can recieve the placed() event modification results - threads.runDelay(() -> tile.block().placed(tile)); - } - } - public class BuildEntity extends TileEntity{ - /**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.*/ + /** + * 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. + */ public Recipe recipe; - public double progress = 0; - public double lastProgress; - public double buildCost; - /**The block that used to be here. - * If a non-recipe block is being deconstructed, this is the block that is being deconstructed.*/ + public float progress = 0; + public float buildCost; + /** + * The block that used to be here. + * If a non-recipe block is being deconstructed, this is the block that is being deconstructed. + */ public Block previous; + public int builderID = -1; - private double[] accumulator; + private float[] accumulator; - public void construct(Unit builder, TileEntity core, double amount){ - double maxProgress = checkRequired(core.items, amount); + public void construct(Unit builder, TileEntity core, float amount){ + float maxProgress = checkRequired(core.items, amount, false); - for (int i = 0; i < recipe.requirements.length; i++) { - accumulator[i] += recipe.requirements[i].amount*maxProgress; //add min amount progressed to the accumulator + for(int i = 0; i < recipe.requirements.length; i++){ + accumulator[i] += recipe.requirements[i].amount * maxProgress; //add min amount progressed to the accumulator } - maxProgress = checkRequired(core.items, maxProgress); + maxProgress = checkRequired(core.items, maxProgress, true); progress = Mathf.clamp(progress + maxProgress); - lastProgress = maxProgress; + if(builder instanceof Player){ + builderID = builder.getID(); + } if(progress >= 1f){ - CallBlocks.onConstructFinish(tile, recipe.result, builder.getID(), tile.getRotation()); + CallBlocks.onConstructFinish(tile, recipe.result, builderID, tile.getRotation(), tile.getTeam()); } } - public void deconstruct(Unit builder, TileEntity core, double amount){ + public void deconstruct(Unit builder, TileEntity core, float amount){ Recipe recipe = Recipe.getByResult(previous); - if(recipe != null) { + if(recipe != null){ ItemStack[] requirements = recipe.requirements; - for (int i = 0; i < requirements.length; i++) { + for(int i = 0; i < requirements.length; i++){ accumulator[i] += requirements[i].amount * amount / 2f; //add scaled amount progressed to the accumulator int accumulated = (int) (accumulator[i]); //get amount - if (amount > 0) { //if it's positive, add it to the core + if(amount > 0){ //if it's positive, add it to the core int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder); - core.tile.block().handleStack(requirements[i].item, accumulated, core.tile, builder); + core.tile.block().handleStack(requirements[i].item, accepting, core.tile, builder); accumulator[i] -= accepting; } @@ -223,28 +234,33 @@ public class BuildBlock extends Block { progress = Mathf.clamp(progress - amount); if(progress <= 0){ - CallBlocks.onDeconstructFinish(tile, recipe == null ? previous : recipe.result); + CallBlocks.onDeconstructFinish(tile, this.recipe == null ? previous : this.recipe.result); } } - private double checkRequired(InventoryModule inventory, double amount){ - double maxProgress = amount; + private float checkRequired(InventoryModule inventory, float amount, boolean remove){ + float maxProgress = amount; - for(int i = 0; i < recipe.requirements.length; i ++){ - int required = (int)(accumulator[i]); //calculate items that are required now + for(int i = 0; i < recipe.requirements.length; i++){ + int required = (int) (accumulator[i]); //calculate items that are required now - if(required > 0){ //if this amount is positive... + if(inventory.get(recipe.requirements[i].item) == 0){ + maxProgress = 0f; + }else if(required > 0){ //if this amount is positive... //calculate how many items it can actually use - int maxUse = Math.min(required, inventory.getItem(recipe.requirements[i].item)); + int maxUse = Math.min(required, inventory.get(recipe.requirements[i].item)); //get this as a fraction - double fraction = maxUse / (double)required; + float fraction = maxUse / (float) required; //move max progress down if this fraction is less than 1 - maxProgress = Math.min(maxProgress, maxProgress*fraction); + maxProgress = Math.min(maxProgress, maxProgress * fraction); + + accumulator[i] -= maxUse; //remove stuff that is actually used - accumulator[i] -= maxUse; - inventory.removeItem(recipe.requirements[i].item, maxUse); + if(remove){ + inventory.remove(recipe.requirements[i].item, maxUse); + } } //else, no items are required yet, so just keep going } @@ -253,13 +269,13 @@ public class BuildBlock extends Block { } public float progress(){ - return (float)progress; + return progress; } public void setConstruct(Block previous, Recipe recipe){ this.recipe = recipe; this.previous = previous; - this.accumulator = new double[recipe.requirements.length]; + this.accumulator = new float[recipe.requirements.length]; this.buildCost = recipe.cost; } @@ -268,7 +284,7 @@ public class BuildBlock extends Block { this.progress = 1f; if(Recipe.getByResult(previous) != null){ this.recipe = Recipe.getByResult(previous); - this.accumulator = new double[Recipe.getByResult(previous).requirements.length]; + this.accumulator = new float[Recipe.getByResult(previous).requirements.length]; this.buildCost = Recipe.getByResult(previous).cost; }else{ this.buildCost = 20f; //default no-recipe build cost is 20 @@ -276,8 +292,8 @@ public class BuildBlock extends Block { } @Override - public void write(DataOutputStream stream) throws IOException { - stream.writeFloat((float)progress); + public void write(DataOutputStream stream) throws IOException{ + stream.writeFloat(progress); stream.writeShort(previous == null ? -1 : previous.id); stream.writeShort(recipe == null ? -1 : recipe.result.id); @@ -285,22 +301,22 @@ public class BuildBlock extends Block { stream.writeByte(-1); }else{ stream.writeByte(accumulator.length); - for(double d : accumulator){ - stream.writeFloat((float)d); + for(float d : accumulator){ + stream.writeFloat(d); } } } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ progress = stream.readFloat(); short pid = stream.readShort(); short rid = stream.readShort(); byte acsize = stream.readByte(); - + if(acsize != -1){ - accumulator = new double[acsize]; - for (int i = 0; i < acsize; i++) { + accumulator = new float[acsize]; + for(int i = 0; i < acsize; i++){ accumulator[i] = stream.readFloat(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/Floor.java b/core/src/io/anuke/mindustry/world/blocks/Floor.java index 435b4f99a6..c03745e90d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/Floor.java +++ b/core/src/io/anuke/mindustry/world/blocks/Floor.java @@ -20,173 +20,173 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; public class Floor extends Block{ - //TODO implement proper bitmasking - protected static IntIntMap bitmask = Mathf.mapInt(2, 1, 8, 2, 10, 3, 11, 4, 16, 5, 18, 6, 22, 7, 24, 8, - 26, 9, 27, 10, 30, 11, 31, 12, 64, 13, 66, 14, 72, 15, 74, 16, 75, 17, 80, 18, - 82, 19, 86, 20, 88, 21, 90, 22, 91, 23, 94, 24, 95, 25, 104, 26, 106, 27, 107, 28, - 120, 29, 122, 30, 123, 31, 126, 32, 127, 33, 208, 34, 210, 35, 214, 36, 216, 37, - 218, 38, 219, 39, 222, 40, 223, 41, 248, 42, 250, 43, 251, 44, 254, 45, 255, 46, 0, 47); - - protected TextureRegion edgeRegion; - protected TextureRegion[] edgeRegions; - protected TextureRegion[] cliffRegions; - protected TextureRegion[] variantRegions; - protected Vector2[] offsets; - protected Predicate blends = block -> block != this && !block.blendOverride(this); - protected boolean blend = true; - - /**edge fallback, used mainly for ores*/ + //TODO implement proper bitmasking + protected static IntIntMap bitmask = Mathf.mapInt(2, 1, 8, 2, 10, 3, 11, 4, 16, 5, 18, 6, 22, 7, 24, 8, + 26, 9, 27, 10, 30, 11, 31, 12, 64, 13, 66, 14, 72, 15, 74, 16, 75, 17, 80, 18, + 82, 19, 86, 20, 88, 21, 90, 22, 91, 23, 94, 24, 95, 25, 104, 26, 106, 27, 107, 28, + 120, 29, 122, 30, 123, 31, 126, 32, 127, 33, 208, 34, 210, 35, 214, 36, 216, 37, + 218, 38, 219, 39, 222, 40, 223, 41, 248, 42, 250, 43, 251, 44, 254, 45, 255, 46, 0, 47); + /** number of different variant regions to use */ + public int variants = 0; + /** edge fallback, used mainly for ores */ public String edge = "stone"; - /**Multiplies unit velocity by this when walked on.*/ - public float speedMultiplier = 1f; - /**Multiplies unit drag by this when walked on.*/ - public float dragMultiplier = 1f; - /**Damage taken per tick on this tile.*/ - public float damageTaken = 0f; - /**How many ticks it takes to drown on this.*/ - public float drownTime = 0f; - /**Effect when walking on this floor.*/ - public Effect walkEffect = BlockFx.ripple; - /**Effect displayed when drowning on this floor.*/ + /** Multiplies unit velocity by this when walked on. */ + public float speedMultiplier = 1f; + /** Multiplies unit drag by this when walked on. */ + public float dragMultiplier = 1f; + /** Damage taken per tick on this tile. */ + public float damageTaken = 0f; + /** How many ticks it takes to drown on this. */ + public float drownTime = 0f; + /** Effect when walking on this floor. */ + public Effect walkEffect = BlockFx.ripple; + /** Effect displayed when drowning on this floor. */ public Effect drownUpdateEffect = BlockFx.bubble; - /**Status effect applied when walking on.*/ - public StatusEffect status = StatusEffects.none; - /**Intensity of applied status effect.*/ - public float statusIntensity = 0.6f; - /**Color of this floor's liquid. Used for tinting sprites.*/ - public Color liquidColor; - /**liquids that drop from this block, used for pumps*/ - public Liquid liquidDrop = null; - /**Whether ores generate on this block.*/ - public boolean hasOres = false; - /**whether this block can be drowned in*/ - public boolean isLiquid; - /**if true, this block cannot be mined by players. useful for annoying things like stone.*/ - public boolean playerUnmineable = false; - - public Floor(String name) { - super(name); - variants = 3; - } + /** Status effect applied when walking on. */ + public StatusEffect status = StatusEffects.none; + /** Intensity of applied status effect. */ + public float statusIntensity = 0.6f; + /** Color of this floor's liquid. Used for tinting sprites. */ + public Color liquidColor; + /** liquids that drop from this block, used for pumps */ + public Liquid liquidDrop = null; + /** Whether ores generate on this block. */ + public boolean hasOres = false; + /** whether this block can be drowned in */ + public boolean isLiquid; + /** if true, this block cannot be mined by players. useful for annoying things like stone. */ + public boolean playerUnmineable = false; + protected TextureRegion edgeRegion; + protected TextureRegion[] edgeRegions; + protected TextureRegion[] cliffRegions; + protected TextureRegion[] variantRegions; + protected Vector2[] offsets; + protected Predicate blends = block -> block != this && !block.blendOverride(this); + protected boolean blend = true; - @Override - public void load() { - super.load(); + public Floor(String name){ + super(name); + variants = 3; + } - if(blend) { - edgeRegion = Draw.hasRegion(name + "edge") ? Draw.region(name + "edge") : Draw.region(edge + "edge"); - edgeRegions = new TextureRegion[8]; - offsets = new Vector2[8]; + @Override + public void load(){ + super.load(); - for(int i = 0; i < 8; i ++){ - int dx = Geometry.d8[i].x, dy = Geometry.d8[i].y; + if(blend){ + edgeRegion = Draw.hasRegion(name + "edge") ? Draw.region(name + "edge") : Draw.region(edge + "edge"); + edgeRegions = new TextureRegion[8]; + offsets = new Vector2[8]; - TextureRegion result = new TextureRegion(); + for(int i = 0; i < 8; i++){ + int dx = Geometry.d8[i].x, dy = Geometry.d8[i].y; - int sx = -dx*8+2, sy = -dy*8+2; - int x = Mathf.clamp(sx, 0, 12); - int y = Mathf.clamp(sy, 0, 12); - int w = Mathf.clamp(sx+8, 0, 12) - x, h = Mathf.clamp(sy+8, 0, 12) - y; + TextureRegion result = new TextureRegion(); - float rx = Mathf.clamp(dx*8, 0, 8-w); - float ry = Mathf.clamp(dy*8, 0, 8-h); + int sx = -dx * 8 + 2, sy = -dy * 8 + 2; + int x = Mathf.clamp(sx, 0, 12); + int y = Mathf.clamp(sy, 0, 12); + int w = Mathf.clamp(sx + 8, 0, 12) - x, h = Mathf.clamp(sy + 8, 0, 12) - y; - result.setTexture(edgeRegion.getTexture()); - result.setRegion(edgeRegion.getRegionX()+x, edgeRegion.getRegionY()+y+h, w, -h); + float rx = Mathf.clamp(dx * 8, 0, 8 - w); + float ry = Mathf.clamp(dy * 8, 0, 8 - h); - edgeRegions[i] = result; - offsets[i] = new Vector2(-4 + rx, -4 + ry); - } + result.setTexture(edgeRegion.getTexture()); + result.setRegion(edgeRegion.getRegionX() + x, edgeRegion.getRegionY() + y + h, w, -h); - cliffRegions = new TextureRegion[4]; - cliffRegions[0] = Draw.region(name + "-cliff-edge-2"); - cliffRegions[1] = Draw.region(name + "-cliff-edge"); - cliffRegions[2] = Draw.region(name + "-cliff-edge-1"); - cliffRegions[3] = Draw.region(name + "-cliff-side"); - } + edgeRegions[i] = result; + offsets[i] = new Vector2(-4 + rx, -4 + ry); + } - //load variant regions for drawing - if(variants > 0){ - variantRegions = new TextureRegion[variants]; + cliffRegions = new TextureRegion[4]; + cliffRegions[0] = Draw.region(name + "-cliff-edge-2"); + cliffRegions[1] = Draw.region(name + "-cliff-edge"); + cliffRegions[2] = Draw.region(name + "-cliff-edge-1"); + cliffRegions[3] = Draw.region(name + "-cliff-side"); + } - for (int i = 0; i < variants; i++) { - variantRegions[i] = Draw.region(name + (i + 1)); - } - }else{ - variantRegions = new TextureRegion[1]; - variantRegions[0] = Draw.region(name); - } - } + //load variant regions for drawing + if(variants > 0){ + variantRegions = new TextureRegion[variants]; - @Override - public void init(){ - super.init(); + for(int i = 0; i < variants; i++){ + variantRegions[i] = Draw.region(name + (i + 1)); + } + }else{ + variantRegions = new TextureRegion[1]; + variantRegions[0] = Draw.region(name); + } + } - if(isLiquid && liquidColor == null){ - throw new RuntimeException("All liquids must define a liquidColor! Problematic block: " + name); - } - } + @Override + public void init(){ + super.init(); - @Override - public void drawNonLayer(Tile tile){ - MathUtils.random.setSeed(tile.id()); + if(isLiquid && liquidColor == null){ + throw new RuntimeException("All liquids must define a liquidColor! Problematic block: " + name); + } + } - drawEdges(tile, true); - } - - @Override - public void draw(Tile tile){ - MathUtils.random.setSeed(tile.id()); + @Override + public void drawNonLayer(Tile tile){ + MathUtils.random.setSeed(tile.id()); - Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length-1))], tile.worldx(), tile.worldy()); + drawEdges(tile, true); + } - if(tile.cliffs != 0 && cliffRegions != null){ - for(int i = 0; i < 4; i ++){ - if((tile.cliffs & (1 << i*2)) != 0) { - Draw.colorl(i > 1 ? 0.6f : 1f); + @Override + public void draw(Tile tile){ + MathUtils.random.setSeed(tile.id()); - boolean above = (tile.cliffs & (1 << ((i+1)%4)*2)) != 0, below = (tile.cliffs & (1 << (Mathf.mod(i-1, 4))*2)) != 0; + Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); - if(above && below){ - Draw.rect(cliffRegions[0], tile.worldx(), tile.worldy(), i * 90); - }else if(above){ - Draw.rect(cliffRegions[1], tile.worldx(), tile.worldy(), i * 90); - }else if(below){ - Draw.rect(cliffRegions[2], tile.worldx(), tile.worldy(), i * 90); - }else{ - Draw.rect(cliffRegions[3], tile.worldx(), tile.worldy(), i * 90); - } - } - } - } - Draw.reset(); + if(tile.cliffs != 0 && cliffRegions != null){ + for(int i = 0; i < 4; i++){ + if((tile.cliffs & (1 << i * 2)) != 0){ + Draw.colorl(i > 1 ? 0.6f : 1f); - drawEdges(tile, false); - } + boolean above = (tile.cliffs & (1 << ((i + 1) % 4) * 2)) != 0, below = (tile.cliffs & (1 << (Mathf.mod(i - 1, 4)) * 2)) != 0; - public boolean blendOverride(Block block){ - return false; - } + if(above && below){ + Draw.rect(cliffRegions[0], tile.worldx(), tile.worldy(), i * 90); + }else if(above){ + Draw.rect(cliffRegions[1], tile.worldx(), tile.worldy(), i * 90); + }else if(below){ + Draw.rect(cliffRegions[2], tile.worldx(), tile.worldy(), i * 90); + }else{ + Draw.rect(cliffRegions[3], tile.worldx(), tile.worldy(), i * 90); + } + } + } + } + Draw.reset(); - protected void drawEdges(Tile tile, boolean sameLayer){ - if(!blend || tile.cliffs > 0) return; + drawEdges(tile, false); + } - for(int i = 0; i < 8; i ++){ - int dx = Geometry.d8[i].x, dy = Geometry.d8[i].y; + public boolean blendOverride(Block block){ + return false; + } - Tile other = world.tile(tile.x+dx, tile.y+dy); + protected void drawEdges(Tile tile, boolean sameLayer){ + if(!blend || tile.cliffs > 0) return; - if(other == null) continue; + for(int i = 0; i < 8; i++){ + int dx = Geometry.d8[i].x, dy = Geometry.d8[i].y; - Floor floor = other.floor(); + Tile other = world.tile(tile.x + dx, tile.y + dy); - if(floor.id <= this.id || !blends.test(floor) || (floor.cacheLayer.ordinal() > this.cacheLayer.ordinal() && !sameLayer) || - (sameLayer && floor.cacheLayer == this.cacheLayer)) continue; + if(other == null) continue; - TextureRegion region = floor.edgeRegions[i]; + Floor floor = other.floor(); - Draw.crect(region, tile.worldx() + floor.offsets[i].x, tile.worldy() + floor.offsets[i].y, region.getRegionWidth(), region.getRegionHeight()); - } - } + if(floor.id <= this.id || !blends.test(floor) || (floor.cacheLayer.ordinal() > this.cacheLayer.ordinal() && !sameLayer) || + (sameLayer && floor.cacheLayer == this.cacheLayer)) continue; -} + TextureRegion region = floor.edgeRegions[i]; + + Draw.crect(region, tile.worldx() + floor.offsets[i].x, tile.worldy() + floor.offsets[i].y, region.getRegionWidth(), region.getRegionHeight()); + } + } + +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/world/blocks/LiquidBlock.java b/core/src/io/anuke/mindustry/world/blocks/LiquidBlock.java index bda16d1167..1d640466c6 100644 --- a/core/src/io/anuke/mindustry/world/blocks/LiquidBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/LiquidBlock.java @@ -2,42 +2,52 @@ package io.anuke.mindustry.world.blocks; import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.blocks.modules.LiquidModule; +import io.anuke.mindustry.world.meta.BlockGroup; +import io.anuke.mindustry.world.modules.LiquidModule; import io.anuke.ucore.graphics.Draw; public class LiquidBlock extends Block{ - protected String liquidRegion = name() + "-liquid"; - - public LiquidBlock(String name) { - super(name); - update = true; - solid = true; - hasLiquids = true; - group = BlockGroup.liquids; - } + protected TextureRegion liquidRegion, bottomRegion, topRegion; - @Override - public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name() + "-bottom"), Draw.region(name() + "-top")}; - } - - @Override - public void draw(Tile tile){ - LiquidModule mod = tile.entity.liquids; + public LiquidBlock(String name){ + super(name); + update = true; + solid = true; + hasLiquids = true; + group = BlockGroup.liquids; + outputsLiquid = true; + } - int rotation = rotate ? tile.getRotation() * 90 : 0; - - Draw.rect(name() + "-bottom", tile.drawx(), tile.drawy(), rotation); - - if(mod.amount > 0.001f){ - Draw.color(mod.liquid.color); - Draw.alpha(mod.amount / liquidCapacity); - Draw.rect(liquidRegion, tile.drawx(), tile.drawy(), rotation); - Draw.color(); - } - - Draw.rect(name() + "-top", tile.drawx(), tile.drawy(), rotation); - } + @Override + public void load(){ + super.load(); + + liquidRegion = Draw.region(name + "-liquid"); + topRegion = Draw.region(name + "-top"); + bottomRegion = Draw.region(name + "-bottom"); + } + + @Override + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name() + "-bottom"), Draw.region(name() + "-top")}; + } + + @Override + public void draw(Tile tile){ + LiquidModule mod = tile.entity.liquids; + + int rotation = rotate ? tile.getRotation() * 90 : 0; + + Draw.rect(bottomRegion, tile.drawx(), tile.drawy(), rotation); + + if(mod.total() > 0.001f){ + Draw.color(mod.current().color); + Draw.alpha(mod.total() / liquidCapacity); + Draw.rect(liquidRegion, tile.drawx(), tile.drawy(), rotation); + Draw.color(); + } + + Draw.rect(topRegion, tile.drawx(), tile.drawy(), rotation); + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/Ore.java b/core/src/io/anuke/mindustry/world/blocks/Ore.java index ff0f155849..398771f070 100644 --- a/core/src/io/anuke/mindustry/world/blocks/Ore.java +++ b/core/src/io/anuke/mindustry/world/blocks/Ore.java @@ -4,9 +4,9 @@ import io.anuke.mindustry.content.blocks.Blocks; public class Ore extends Floor{ - public Ore(String name) { - super(name); - blends = block -> block != this && block != Blocks.stone; - } + public Ore(String name){ + super(name); + blends = block -> block != this && block != Blocks.stone; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/OreBlock.java b/core/src/io/anuke/mindustry/world/blocks/OreBlock.java index 18fcd86711..57c7f67aa2 100644 --- a/core/src/io/anuke/mindustry/world/blocks/OreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/OreBlock.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.Tile; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public class OreBlock extends Floor { +public class OreBlock extends Floor{ public Floor base; public OreBlock(Item ore, Floor base){ @@ -32,7 +32,7 @@ public class OreBlock extends Floor { @Override public void draw(Tile tile){ - Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length-1))], tile.worldx(), tile.worldy()); + Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); drawEdges(tile, false); } @@ -45,7 +45,7 @@ public class OreBlock extends Floor { } @Override - public boolean blendOverride(Block block) { + public boolean blendOverride(Block block){ return block == base; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/PowerBlock.java b/core/src/io/anuke/mindustry/world/blocks/PowerBlock.java index 095aa42034..83e550a7e4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/PowerBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/PowerBlock.java @@ -4,12 +4,12 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.meta.BlockGroup; public abstract class PowerBlock extends Block{ - - public PowerBlock(String name) { - super(name); - update = true; - solid = true; - hasPower = true; - group = BlockGroup.power; - } + + public PowerBlock(String name){ + super(name); + update = true; + solid = true; + hasPower = true; + group = BlockGroup.power; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/Rock.java b/core/src/io/anuke/mindustry/world/blocks/Rock.java index f6c463ece5..f5771124fe 100644 --- a/core/src/io/anuke/mindustry/world/blocks/Rock.java +++ b/core/src/io/anuke/mindustry/world/blocks/Rock.java @@ -1,13 +1,51 @@ package io.anuke.mindustry.world.blocks; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.util.Mathf; -public class Rock extends Block { +public class Rock extends Block{ + protected TextureRegion[] shadowRegions, regions; + protected int variants; - public Rock(String name) { + public Rock(String name){ super(name); - varyShadow = true; breakable = true; alwaysReplace = true; } + + @Override + public void draw(Tile tile){ + if(variants > 0){ + Draw.rect(regions[Mathf.randomSeed(tile.id(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy()); + }else{ + Draw.rect(region, tile.worldx(), tile.worldy()); + } + } + + @Override + public void drawShadow(Tile tile){ + if(shadowRegions != null){ + Draw.rect(shadowRegions[(Mathf.randomSeed(tile.id(), 0, variants - 1))], tile.worldx(), tile.worldy()); + }else if(shadowRegion != null){ + Draw.rect(shadowRegion, tile.drawx(), tile.drawy()); + } + } + + @Override + public void load(){ + super.load(); + + if(variants > 0){ + shadowRegions = new TextureRegion[variants]; + regions = new TextureRegion[variants]; + + for(int i = 0; i < variants; i++){ + shadowRegions[i] = Draw.region(name + "shadow" + (i + 1)); + regions[i] = Draw.region(name + (i + 1)); + } + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/SelectionTrait.java b/core/src/io/anuke/mindustry/world/blocks/SelectionTrait.java index 615acb974a..45ba5bb105 100644 --- a/core/src/io/anuke/mindustry/world/blocks/SelectionTrait.java +++ b/core/src/io/anuke/mindustry/world/blocks/SelectionTrait.java @@ -12,7 +12,7 @@ import io.anuke.ucore.scene.ui.layout.Table; import static io.anuke.mindustry.Vars.control; -public interface SelectionTrait { +public interface SelectionTrait{ default void buildItemTable(Table table, Supplier holder, Consumer consumer){ @@ -32,7 +32,7 @@ public interface SelectionTrait { button.getStyle().imageUp = new TextureRegionDrawable(new TextureRegion(items.get(i).region)); button.setChecked(holder.get().id == f); - if(i++%4 == 3){ + if(i++ % 4 == 3){ cont.row(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/StaticBlock.java b/core/src/io/anuke/mindustry/world/blocks/StaticBlock.java index 61f11a5549..c39015cff9 100644 --- a/core/src/io/anuke/mindustry/world/blocks/StaticBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/StaticBlock.java @@ -5,9 +5,9 @@ import io.anuke.mindustry.world.Block; public class StaticBlock extends Block{ - public StaticBlock(String name) { - super(name); - cacheLayer = CacheLayer.walls; - } + public StaticBlock(String name){ + super(name); + cacheLayer = CacheLayer.walls; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/Wall.java b/core/src/io/anuke/mindustry/world/blocks/Wall.java index e28fc5d7e5..e2cb089f92 100644 --- a/core/src/io/anuke/mindustry/world/blocks/Wall.java +++ b/core/src/io/anuke/mindustry/world/blocks/Wall.java @@ -5,16 +5,16 @@ import io.anuke.mindustry.world.meta.BlockGroup; public class Wall extends Block{ - public Wall(String name) { - super(name); - solid = true; - destructible = true; - group = BlockGroup.walls; - } + public Wall(String name){ + super(name); + solid = true; + destructible = true; + group = BlockGroup.walls; + } - @Override - public boolean canReplace(Block other){ - return super.canReplace(other) && health > other.health; - } + @Override + public boolean canReplace(Block other){ + return super.canReplace(other) && health > other.health; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java index 1f39e386f9..c8c72c9439 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java @@ -16,13 +16,13 @@ import io.anuke.ucore.util.Physics; import static io.anuke.mindustry.Vars.tilesize; -public class DeflectorWall extends Wall { +public class DeflectorWall extends Wall{ static final float hitTime = 10f; protected float maxDamageDeflect = 5f; protected Rectangle rect = new Rectangle(); - public DeflectorWall(String name) { + public DeflectorWall(String name){ super(name); } @@ -41,7 +41,7 @@ public class DeflectorWall extends Wall { Draw.rect("blank", tile.drawx(), tile.drawy(), tilesize * size, tilesize * size); Draw.reset(); - entity.hit = Mathf.clamp(entity.hit - Timers.delta()/hitTime); + entity.hit = Mathf.clamp(entity.hit - Timers.delta() / hitTime); Graphics.setNormalBlending(); } @@ -56,13 +56,13 @@ public class DeflectorWall extends Wall { float penX = Math.abs(entity.x - bullet.x), penY = Math.abs(entity.y - bullet.y); Vector2 position = Physics.raycastRect(bullet.lastPosition().x, bullet.lastPosition().y, bullet.x, bullet.y, - rect.setCenter(entity.x, entity.y).setSize(size * tilesize + bullet.hitbox.width + bullet.hitbox.height)); + rect.setCenter(entity.x, entity.y).setSize(size * tilesize + bullet.hitbox.width + bullet.hitbox.height)); if(position != null){ bullet.set(position.x, position.y); } - if(penX > penY) { + if(penX > penY){ bullet.getVelocity().x *= -1; }else{ bullet.getVelocity().y *= -1; @@ -73,11 +73,11 @@ public class DeflectorWall extends Wall { bullet.scaleTime(1f); bullet.supressCollision(); - ((DeflectorEntity)entity).hit = 1f; + ((DeflectorEntity) entity).hit = 1f; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new DeflectorEntity(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/Door.java b/core/src/io/anuke/mindustry/world/blocks/defense/Door.java index c147d97e48..d186815e23 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/Door.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/Door.java @@ -20,86 +20,86 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.threads; public class Door extends Wall{ - protected final Rectangle rect = new Rectangle(); + protected final Rectangle rect = new Rectangle(); - protected Effect openfx = BlockFx.dooropen; - protected Effect closefx = BlockFx.doorclose; + protected Effect openfx = BlockFx.dooropen; + protected Effect closefx = BlockFx.doorclose; - protected TextureRegion openRegion; + protected TextureRegion openRegion; - public Door(String name) { - super(name); - solid = false; - solidifes = true; - consumesTap = true; - } + public Door(String name){ + super(name); + solid = false; + solidifes = true; + consumesTap = true; + } - @Override - public void load() { - super.load(); - openRegion = Draw.region(name + "-open"); - } + @Override + public void load(){ + super.load(); + openRegion = Draw.region(name + "-open"); + } - @Override - public void draw(Tile tile){ - DoorEntity entity = tile.entity(); - - if(!entity.open){ - Draw.rect(name, tile.drawx(), tile.drawy()); - }else{ - Draw.rect(openRegion, tile.drawx(), tile.drawy()); - } - } + @Override + public void draw(Tile tile){ + DoorEntity entity = tile.entity(); - @Override - public CursorType getCursor(Tile tile){ - return CursorType.hand; - } - - @Override - public boolean isSolidFor(Tile tile){ - DoorEntity entity = tile.entity(); - return !entity.open; - } + if(!entity.open){ + Draw.rect(region, tile.drawx(), tile.drawy()); + }else{ + Draw.rect(openRegion, tile.drawx(), tile.drawy()); + } + } - @Override - public void tapped(Tile tile, Player player){ - DoorEntity entity = tile.entity(); + @Override + public CursorType getCursor(Tile tile){ + return CursorType.hand; + } - threads.run(() -> { + @Override + public boolean isSolidFor(Tile tile){ + DoorEntity entity = tile.entity(); + return !entity.open; + } - if(Units.anyEntities(tile) && entity.open){ - return; - } + @Override + public void tapped(Tile tile, Player player){ + DoorEntity entity = tile.entity(); - entity.open = !entity.open; - if(!entity.open){ - Effects.effect(closefx, tile.drawx(), tile.drawy()); - }else{ - Effects.effect(openfx, tile.drawx(), tile.drawy()); - } - }); - } - - @Override - public TileEntity getEntity(){ - return new DoorEntity(); - } - - public class DoorEntity extends TileEntity{ - public boolean open = false; - - @Override - public void write(DataOutputStream stream) throws IOException{ - super.write(stream); - stream.writeBoolean(open); - } - - @Override - public void read(DataInputStream stream) throws IOException{ - super.read(stream); - open = stream.readBoolean(); - } - } + threads.run(() -> { + + if(Units.anyEntities(tile) && entity.open){ + return; + } + + entity.open = !entity.open; + if(!entity.open){ + Effects.effect(closefx, tile.drawx(), tile.drawy()); + }else{ + Effects.effect(openfx, tile.drawx(), tile.drawy()); + } + }); + } + + @Override + public TileEntity getEntity(){ + return new DoorEntity(); + } + + public class DoorEntity extends TileEntity{ + public boolean open = false; + + @Override + public void write(DataOutputStream stream) throws IOException{ + super.write(stream); + stream.writeBoolean(open); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + super.read(stream); + open = stream.readBoolean(); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/PhaseWall.java b/core/src/io/anuke/mindustry/world/blocks/defense/PhaseWall.java index 073968c565..6127a8b469 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/PhaseWall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/PhaseWall.java @@ -5,16 +5,16 @@ import io.anuke.mindustry.world.blocks.Wall; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Mathf; -public class PhaseWall extends Wall { +public class PhaseWall extends Wall{ protected float regenSpeed = 0.25f; - public PhaseWall(String name) { + public PhaseWall(String name){ super(name); update = true; } @Override - public void update(Tile tile) { + public void update(Tile tile){ tile.entity.health = Mathf.clamp(tile.entity.health + regenSpeed * Timers.delta(), 0f, health); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/ShieldBlock.java b/core/src/io/anuke/mindustry/world/blocks/defense/ShieldBlock.java index 80984d505f..b87dc6ac4e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/ShieldBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/ShieldBlock.java @@ -11,71 +11,71 @@ import io.anuke.ucore.util.Mathf; //TODO remove public class ShieldBlock extends PowerBlock{ - public float shieldRadius = 40f; - public float powerDrain = 0.005f; - public float powerPerDamage = 0.06f; - public float maxRadius = 40f; - public float radiusScale = 300f; - - public ShieldBlock(String name) { - super(name); - powerCapacity = 80f; - } - - @Override - public void setStats(){ - super.setStats(); - //stats.add("powersecond", Strings.toFixed(powerDrain*60, 2)); - //stats.add("powerdraindamage", Strings.toFixed(powerPerDamage, 2)); - //stats.add("shieldradius", (int)shieldRadius); - } + public float shieldRadius = 40f; + public float powerDrain = 0.005f; + public float powerPerDamage = 0.06f; + public float maxRadius = 40f; + public float radiusScale = 300f; - @Override - public void update(Tile tile){ - ShieldEntity entity = tile.entity(); + public ShieldBlock(String name){ + super(name); + powerCapacity = 80f; + } - if(entity.shield == null){ - entity.shield = new Shield(tile); - if(Vars.infiniteAmmo && Vars.debug) - entity.shield.add(); - } + @Override + public void setStats(){ + super.setStats(); + //stats.add("powersecond", Strings.toFixed(powerDrain*60, 2)); + //stats.add("powerdraindamage", Strings.toFixed(powerPerDamage, 2)); + //stats.add("shieldradius", (int)shieldRadius); + } - if(entity.power.amount > powerPerDamage){ - if(!entity.shield.active){ - entity.shield.add(); - } + @Override + public void update(Tile tile){ + ShieldEntity entity = tile.entity(); - entity.power.amount -= powerDrain * Timers.delta(); - }else{ - if(entity.shield.active && !(Vars.infiniteAmmo && Vars.debug)){ - entity.shield.removeDelay(); - } - } - - entity.shield.radius = Mathf.lerp(entity.shield.radius, Math.min(entity.power.amount / powerCapacity * radiusScale, maxRadius), Timers.delta() * 0.05f); + if(entity.shield == null){ + entity.shield = new Shield(tile); + if(Vars.infiniteAmmo && Vars.debug) + entity.shield.add(); + } - } + if(entity.power.amount > powerPerDamage){ + if(!entity.shield.active){ + entity.shield.add(); + } - @Override - public TileEntity getEntity(){ - return new ShieldEntity(); - } - - public void handleBullet(Tile tile, BulletEntity bullet){ - ShieldEntity entity = tile.entity(); - - if(entity.power.amount < bullet.getDamage() * powerPerDamage){ - return; - } - - bullet.remove(); - //Effects.effect(bullet.damage > 5 ? BulletFx.shieldhit : BulletFx.laserhit, bullet); - //if(!headless) renderer.addShieldHit(bullet.x, bullet.y); - - entity.power.amount -= bullet.getDamage() * powerPerDamage; - } + entity.power.amount -= powerDrain * Timers.delta(); + }else{ + if(entity.shield.active && !(Vars.infiniteAmmo && Vars.debug)){ + entity.shield.removeDelay(); + } + } - static class ShieldEntity extends TileEntity{ - Shield shield; - } + entity.shield.radius = Mathf.lerp(entity.shield.radius, Math.min(entity.power.amount / powerCapacity * radiusScale, maxRadius), Timers.delta() * 0.05f); + + } + + @Override + public TileEntity getEntity(){ + return new ShieldEntity(); + } + + public void handleBullet(Tile tile, BulletEntity bullet){ + ShieldEntity entity = tile.entity(); + + if(entity.power.amount < bullet.getDamage() * powerPerDamage){ + return; + } + + bullet.remove(); + //Effects.effect(bullet.damage > 5 ? BulletFx.shieldhit : BulletFx.laserhit, bullet); + //if(!headless) renderer.addShieldHit(bullet.x, bullet.y); + + entity.power.amount -= bullet.getDamage() * powerPerDamage; + } + + static class ShieldEntity extends TileEntity{ + Shield shield; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/ShieldedWallBlock.java b/core/src/io/anuke/mindustry/world/blocks/defense/ShieldedWallBlock.java index 261836887b..9416aa1258 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/ShieldedWallBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/ShieldedWallBlock.java @@ -11,66 +11,66 @@ import static io.anuke.mindustry.Vars.tilesize; //TODO remove public class ShieldedWallBlock extends PowerBlock{ - static final float hitTime = 18f; - static final Color hitColor = Color.SKY.cpy().mul(1.2f); - public float powerPerDamage = 0.08f; + static final float hitTime = 18f; + static final Color hitColor = Color.SKY.cpy().mul(1.2f); + public float powerPerDamage = 0.08f; - public ShieldedWallBlock(String name) { - super(name); - destructible = true; - update = false; - } - - @Override - public float handleDamage(Tile tile, float amount){ - float drain = amount * powerPerDamage; - ShieldedWallEntity entity = tile.entity(); - - if(entity.power.amount > drain){ - entity.power.amount -= drain; - entity.hit = hitTime; - return 0; - }else if(entity.power.amount > 0){ - int reduction = (int)(entity.power.amount / powerPerDamage); - entity.power.amount = 0; - - return amount - reduction; - } - - return amount; - } + public ShieldedWallBlock(String name){ + super(name); + destructible = true; + update = false; + } - @Override - public void setStats(){ - super.setStats(); - //stats.add("powerdraindamage", Strings.toFixed(powerPerDamage, 2)); - } - - @Override - public void draw(Tile tile){ - super.draw(tile); - - ShieldedWallEntity entity = tile.entity(); - - if(entity.power.amount > powerPerDamage){ - //renderer.addShield(() -> Draw.rect("blank", tile.worldx(), tile.worldy(), tilesize, tilesize)); - } - - Draw.color(hitColor); - Draw.alpha(entity.hit / hitTime * 0.9f); - Draw.rect("blank", tile.worldx(), tile.worldy(), tilesize, tilesize); - Draw.reset(); - - entity.hit -= Timers.delta(); - entity.hit = Math.max(entity.hit, 0); - } - - @Override - public TileEntity getEntity(){ - return new ShieldedWallEntity(); - } - - static class ShieldedWallEntity extends TileEntity{ - public float hit; - } + @Override + public float handleDamage(Tile tile, float amount){ + float drain = amount * powerPerDamage; + ShieldedWallEntity entity = tile.entity(); + + if(entity.power.amount > drain){ + entity.power.amount -= drain; + entity.hit = hitTime; + return 0; + }else if(entity.power.amount > 0){ + int reduction = (int) (entity.power.amount / powerPerDamage); + entity.power.amount = 0; + + return amount - reduction; + } + + return amount; + } + + @Override + public void setStats(){ + super.setStats(); + //stats.add("powerdraindamage", Strings.toFixed(powerPerDamage, 2)); + } + + @Override + public void draw(Tile tile){ + super.draw(tile); + + ShieldedWallEntity entity = tile.entity(); + + if(entity.power.amount > powerPerDamage){ + //renderer.addShield(() -> Draw.rect("blank", tile.worldx(), tile.worldy(), tilesize, tilesize)); + } + + Draw.color(hitColor); + Draw.alpha(entity.hit / hitTime * 0.9f); + Draw.rect("blank", tile.worldx(), tile.worldy(), tilesize, tilesize); + Draw.reset(); + + entity.hit -= Timers.delta(); + entity.hit = Math.max(entity.hit, 0); + } + + @Override + public TileEntity getEntity(){ + return new ShieldedWallEntity(); + } + + static class ShieldedWallEntity extends TileEntity{ + public float hit; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java index 853695ba46..3e1f66e7dc 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java @@ -9,11 +9,13 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -/**Artillery turrets have special shooting calculations done to hit targets.*/ -public class ArtilleryTurret extends ItemTurret { +/** + * Artillery turrets have special shooting calculations done to hit targets. + */ +public class ArtilleryTurret extends ItemTurret{ protected float velocityInaccuracy = 0f; - public ArtilleryTurret(String name) { + public ArtilleryTurret(String name){ super(name); targetAir = false; } @@ -34,9 +36,9 @@ public class ArtilleryTurret extends ItemTurret { float dst = entity.distanceTo(predict.x, predict.y); float maxTraveled = type.bullet.lifetime * type.bullet.speed; - for (int i = 0; i < shots; i++) { + for(int i = 0; i < shots; i++){ Bullet.create(ammo.bullet, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, - entity.rotation + Mathf.range(inaccuracy + type.inaccuracy), dst/maxTraveled + Mathf.range(velocityInaccuracy)); + entity.rotation + Mathf.range(inaccuracy + type.inaccuracy), dst / maxTraveled + Mathf.range(velocityInaccuracy)); } effects(tile); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java index 1093721863..c31fe33cd4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java @@ -7,11 +7,11 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public class BurstTurret extends ItemTurret { +public class BurstTurret extends ItemTurret{ protected float burstSpacing = 5; protected float xRand = 0f; - public BurstTurret(String name) { + public BurstTurret(String name){ super(name); } @@ -21,7 +21,7 @@ public class BurstTurret extends ItemTurret { entity.heat = 1f; - for (int i = 0; i < shots; i++) { + for(int i = 0; i < shots; i++){ Timers.run(burstSpacing * i, () -> { if(!(tile.entity instanceof TurretEntity) || !hasAmmo(tile)) return; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java index b1588f85af..62c832f6ac 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java @@ -4,8 +4,7 @@ import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.values.LiquidFilterValue; +import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; @@ -13,48 +12,48 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public class CooledTurret extends Turret { - /**How much reload is lowered by for each unit of liquid of heat capacity 1.*/ +public class CooledTurret extends Turret{ + /** + * How much reload is lowered by for each unit of liquid of heat capacity 1. + */ protected float coolantMultiplier = 1f; - /**Max coolant used per tick.*/ + /** + * Max coolant used per tick. + */ protected float maxUsed = 1f; protected Effect coolEffect = BlockFx.fuelburn; - public CooledTurret(String name) { + public CooledTurret(String name){ super(name); hasLiquids = true; liquidCapacity = 20f; + + consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f, 0.01f)).update(false).optional(true); } @Override - public void setStats() { - super.setStats(); - - stats.add(BlockStat.inputLiquidAux, new LiquidFilterValue(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.2f)); - } - - @Override - protected void updateShooting(Tile tile) { + protected void updateShooting(Tile tile){ super.updateShooting(tile); TurretEntity entity = tile.entity(); + Liquid liquid = entity.liquids.current(); - float used = Math.min(Math.min(entity.liquids.amount, maxUsed * Timers.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / entity.liquids.liquid.heatCapacity)); - entity.reload += (used * entity.liquids.liquid.heatCapacity) / entity.liquids.liquid.heatCapacity; - entity.liquids.amount -= used; + float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Timers.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)); + entity.reload += (used * liquid.heatCapacity) / liquid.heatCapacity; + entity.liquids.remove(liquid, used); if(Mathf.chance(0.04 * used)){ - Effects.effect(coolEffect, tile.drawx() + Mathf.range(size * tilesize/2f), tile.drawy() + Mathf.range(size * tilesize/2f)); + Effects.effect(coolEffect, tile.drawx() + Mathf.range(size * tilesize / 2f), tile.drawy() + Mathf.range(size * tilesize / 2f)); } //don't use oil as coolant, thanks - if(Mathf.chance(entity.liquids.liquid.flammability / 10f * used)){ + if(Mathf.chance(liquid.flammability / 10f * used)){ Fire.create(tile); } } @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ return super.acceptLiquid(tile, source, liquid, amount) && liquid.temperature <= 0.5f; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java index 1a46cb7be9..1601b15a4c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java @@ -6,10 +6,10 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public class DoubleTurret extends ItemTurret { +public class DoubleTurret extends ItemTurret{ protected float shotWidth = 2f; - public DoubleTurret(String name) { + public DoubleTurret(String name){ super(name); shots = 2; } @@ -17,7 +17,7 @@ public class DoubleTurret extends ItemTurret { @Override protected void shoot(Tile tile, AmmoType ammo){ TurretEntity entity = tile.entity(); - entity.shots ++; + entity.shots++; int i = Mathf.signs[entity.shots % 2]; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java index 1fdfbdc39d..b982ff5a0b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -11,18 +11,18 @@ import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.values.ItemFilterValue; -public class ItemTurret extends CooledTurret { +public class ItemTurret extends CooledTurret{ protected int maxAmmo = 50; protected AmmoType[] ammoTypes; protected ObjectMap ammoMap = new ObjectMap<>(); - public ItemTurret(String name) { + public ItemTurret(String name){ super(name); hasItems = true; } @Override - public void setStats() { + public void setStats(){ super.setStats(); stats.remove(BlockStat.itemCapacity); @@ -31,51 +31,51 @@ public class ItemTurret extends CooledTurret { } @Override - public int acceptStack(Item item, int amount, Tile tile, Unit source) { + public int acceptStack(Item item, int amount, Tile tile, Unit source){ TurretEntity entity = tile.entity(); AmmoType type = ammoMap.get(item); if(type == null) return 0; - return Math.min((int)((maxAmmo - entity.totalAmmo) / ammoMap.get(item).quantityMultiplier), amount); + return Math.min((int) ((maxAmmo - entity.totalAmmo) / ammoMap.get(item).quantityMultiplier), amount); } - + @Override public void handleStack(Item item, int amount, Tile tile, Unit source){ - for (int i = 0; i < amount; i++) { + for(int i = 0; i < amount; i++){ handleItem(item, tile, null); } } //currently can't remove items from turrets. @Override - public int removeStack(Tile tile, Item item, int amount) { + public int removeStack(Tile tile, Item item, int amount){ return 0; } @Override - public void handleItem(Item item, Tile tile, Tile source) { + public void handleItem(Item item, Tile tile, Tile source){ TurretEntity entity = tile.entity(); AmmoType type = ammoMap.get(item); entity.totalAmmo += type.quantityMultiplier; - entity.items.addItem(item, 1); + entity.items.add(item, 1); //find ammo entry by type - for(int i = 0; i < entity.ammo.size; i ++){ + for(int i = 0; i < entity.ammo.size; i++){ AmmoEntry entry = entity.ammo.get(i); //if found, put it to the right if(entry.type == type){ entry.amount += type.quantityMultiplier; - entity.ammo.swap(i, entity.ammo.size-1); + entity.ammo.swap(i, entity.ammo.size - 1); return; } } //must not be found - AmmoEntry entry = new AmmoEntry(type, (int)type.quantityMultiplier); + AmmoEntry entry = new AmmoEntry(type, (int) type.quantityMultiplier); entity.ammo.add(entry); } @@ -89,19 +89,19 @@ public class ItemTurret extends CooledTurret { @Override public void setBars(){ super.setBars(); - bars.replace(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity().totalAmmo / maxAmmo)); + bars.replace(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity().totalAmmo / maxAmmo)); } @Override public void init(){ super.init(); - if(ammoTypes != null) { - for (AmmoType type : ammoTypes) { + if(ammoTypes != null){ + for(AmmoType type : ammoTypes){ if(type.item == null) continue; - if (ammoMap.containsKey(type.item)) { + if(ammoMap.containsKey(type.item)){ throw new RuntimeException("Turret \"" + name + "\" has two conflicting ammo entries on item type " + type.item + "!"); - } else { + }else{ ammoMap.put(type.item, type); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java index 1b69866132..63115407cf 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -10,7 +10,7 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public class LaserTurret extends PowerTurret { +public class LaserTurret extends PowerTurret{ protected float chargeTime = 30f; protected int chargeEffects = 5; @@ -18,7 +18,7 @@ public class LaserTurret extends PowerTurret { protected Effect chargeEffect = Fx.none; protected Effect chargeBeginEffect = Fx.none; - public LaserTurret(String name) { + public LaserTurret(String name){ super(name); } @@ -31,7 +31,7 @@ public class LaserTurret extends PowerTurret { tr.trns(entity.rotation, size * tilesize / 2); Effects.effect(chargeBeginEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - for(int i = 0; i < chargeEffects; i ++){ + for(int i = 0; i < chargeEffects; i++){ Timers.run(Mathf.random(chargeMaxDelay), () -> { if(!isTurret(tile)) return; tr.trns(entity.rotation, size * tilesize / 2); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 80f84af7ed..e053be47e1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -11,27 +11,27 @@ import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.values.LiquidFilterValue; import io.anuke.ucore.core.Effects; -public abstract class LiquidTurret extends Turret { +public abstract class LiquidTurret extends Turret{ protected AmmoType[] ammoTypes; protected ObjectMap liquidAmmoMap = new ObjectMap<>(); - public LiquidTurret(String name) { + public LiquidTurret(String name){ super(name); hasLiquids = true; } @Override - public void setStats() { + public void setStats(){ super.setStats(); stats.add(BlockStat.inputLiquid, new LiquidFilterValue(item -> liquidAmmoMap.containsKey(item))); } @Override - public void setBars() { + public void setBars(){ super.setBars(); bars.remove(BarType.inventory); - bars.replace(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.amount / liquidCapacity)); + bars.replace(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.total() / liquidCapacity)); } @Override @@ -43,7 +43,7 @@ public abstract class LiquidTurret extends Turret { Effects.effect(shootEffect, type.liquid.color, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); Effects.effect(smokeEffect, type.liquid.color, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - if (shootShake > 0) { + if(shootShake > 0){ Effects.shake(shootShake, shootShake, tile.entity); } @@ -53,43 +53,44 @@ public abstract class LiquidTurret extends Turret { @Override public AmmoType useAmmo(Tile tile){ TurretEntity entity = tile.entity(); - AmmoType type = liquidAmmoMap.get(entity.liquids.liquid); - entity.liquids.amount -= type.quantityMultiplier; + AmmoType type = liquidAmmoMap.get(entity.liquids.current()); + entity.liquids.remove(type.liquid, type.quantityMultiplier); return type; } @Override public AmmoType peekAmmo(Tile tile){ - return liquidAmmoMap.get(tile.entity.liquids.liquid); + return liquidAmmoMap.get(tile.entity.liquids.current()); } @Override public boolean hasAmmo(Tile tile){ TurretEntity entity = tile.entity(); - return liquidAmmoMap.get(entity.liquids.liquid) != null && entity.liquids.amount >= liquidAmmoMap.get(entity.liquids.liquid).quantityMultiplier; + return liquidAmmoMap.get(entity.liquids.current()) != null && entity.liquids.total() >= liquidAmmoMap.get(entity.liquids.current()).quantityMultiplier; } @Override public void init(){ super.init(); - for (AmmoType type : ammoTypes) { - if (liquidAmmoMap.containsKey(type.liquid)) { + for(AmmoType type : ammoTypes){ + if(liquidAmmoMap.containsKey(type.liquid)){ throw new RuntimeException("Turret \"" + name + "\" has two conflicting ammo entries on liquid type " + type.liquid + "!"); - } else { + }else{ liquidAmmoMap.put(type.liquid, type); } } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return false; } @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return super.acceptLiquid(tile, source, liquid, amount) && liquidAmmoMap.get(liquid) != null; + return super.acceptLiquid(tile, source, liquid, amount) && liquidAmmoMap.get(liquid) != null + && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.01f); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java index da4580cd2b..0c1b84698f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -5,35 +5,35 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; -public abstract class PowerTurret extends CooledTurret { - protected float powerUsed = 0.5f; - protected AmmoType shootType; +public abstract class PowerTurret extends CooledTurret{ + protected float powerUsed = 0.5f; + protected AmmoType shootType; - public PowerTurret(String name) { - super(name); - hasPower = true; - } - - @Override - public void setStats(){ - super.setStats(); + public PowerTurret(String name){ + super(name); + hasPower = true; + } - stats.add(BlockStat.powerShot, powerUsed, StatUnit.powerUnits); - } - - @Override - public boolean hasAmmo(Tile tile){ - return tile.entity.power.amount >= powerUsed; - } + @Override + public void setStats(){ + super.setStats(); - @Override - public AmmoType useAmmo(Tile tile){ - tile.entity.power.amount -= powerUsed; - return shootType; - } + stats.add(BlockStat.powerShot, powerUsed, StatUnit.powerUnits); + } - @Override - public AmmoType peekAmmo(Tile tile) { - return shootType; - } + @Override + public boolean hasAmmo(Tile tile){ + return tile.entity.power.amount >= powerUsed; + } + + @Override + public AmmoType useAmmo(Tile tile){ + tile.entity.power.amount -= powerUsed; + return shootType; + } + + @Override + public AmmoType peekAmmo(Tile tile){ + return shootType; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java index 9feeb9d9a3..a6171e6cb5 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java @@ -27,7 +27,10 @@ import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.BiConsumer; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; -import io.anuke.ucore.util.*; +import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Mathf; +import io.anuke.ucore.util.ThreadArray; +import io.anuke.ucore.util.Translator; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -36,297 +39,304 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tilesize; public abstract class Turret extends Block{ - protected static final int targetInterval = 15; - - protected final int timerTarget = timers++; + protected static final int targetInterval = 15; - protected Color heatColor = Palette.turretHeat; - protected Effect shootEffect = Fx.none; - protected Effect smokeEffect = Fx.none; - protected Effect ammoUseEffect = Fx.none; + protected final int timerTarget = timers++; + + protected Color heatColor = Palette.turretHeat; + protected Effect shootEffect = Fx.none; + protected Effect smokeEffect = Fx.none; + protected Effect ammoUseEffect = Fx.none; protected int ammoPerShot = 1; protected float ammoEjectBack = 1f; - protected float range = 50f; - protected float reload = 10f; - protected float inaccuracy = 0f; - protected int shots = 1; - protected float recoil = 1f; - protected float restitution = 0.02f; - protected float cooldown = 0.02f; - protected float rotatespeed = 5f; //in degrees per tick - protected float shootCone = 8f; - protected float shootShake = 0f; - protected boolean targetAir = true; + protected float range = 50f; + protected float reload = 10f; + protected float inaccuracy = 0f; + protected int shots = 1; + protected float recoil = 1f; + protected float restitution = 0.02f; + protected float cooldown = 0.02f; + protected float rotatespeed = 5f; //in degrees per tick + protected float shootCone = 8f; + protected float shootShake = 0f; + protected boolean targetAir = true; - protected Translator tr = new Translator(); - protected Translator tr2 = new Translator(); + protected Translator tr = new Translator(); + protected Translator tr2 = new Translator(); - protected TextureRegion baseRegion; - protected TextureRegion heatRegion; - protected TextureRegion baseTopRegion; + protected TextureRegion baseRegion; + protected TextureRegion heatRegion; + protected TextureRegion baseTopRegion; - protected BiConsumer drawer = (tile, entity) -> Draw.rect(name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - protected BiConsumer heatDrawer = (tile, entity) ->{ - Graphics.setAdditiveBlending(); - Draw.color(heatColor); - Draw.alpha(entity.heat); - Draw.rect(heatRegion, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - Graphics.setNormalBlending(); - }; + protected BiConsumer drawer = (tile, entity) -> Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + protected BiConsumer heatDrawer = (tile, entity) -> { + if(entity.heat <= 0.00001f) return; + Graphics.setAdditiveBlending(); + Draw.color(heatColor); + Draw.alpha(entity.heat); + Draw.rect(heatRegion, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + Graphics.setNormalBlending(); + }; - public Turret(String name) { - super(name); - update = true; - solid = true; - layer = Layer.turret; - group = BlockGroup.turrets; - } + public Turret(String name){ + super(name); + update = true; + solid = true; + layer = Layer.turret; + group = BlockGroup.turrets; + } - @Override - public void init() { - super.init(); - viewRange = range; - } + @Override + public void init(){ + super.init(); + viewRange = range; + } - @Override - public void load() { - super.load(); + @Override + public void load(){ + super.load(); - baseRegion = Draw.region("block-" + size); - baseTopRegion = Draw.region("block-" +size + "-top"); - heatRegion = Draw.region(name + "-heat"); - } + baseRegion = Draw.region("block-" + size); + baseTopRegion = Draw.region("block-" + size + "-top"); + heatRegion = Draw.region(name + "-heat"); + } - @Override - public void setStats(){ - super.setStats(); + @Override + public void setStats(){ + super.setStats(); /* if(ammo != null) stats.add("ammo", ammo); if(ammo != null) stats.add("ammocapacity", maxAmmo); if(ammo != null) stats.add("ammoitem", ammoMultiplier);*/ - stats.add(BlockStat.shootRange, range, StatUnit.blocks); - stats.add(BlockStat.inaccuracy, (int)inaccuracy, StatUnit.degrees); - stats.add(BlockStat.reload, 60f/reload, StatUnit.seconds); - stats.add(BlockStat.shots, shots, StatUnit.none); - stats.add(BlockStat.targetsAir, targetAir); - } - - @Override - public void draw(Tile tile){ - Draw.rect(baseRegion, tile.drawx(), tile.drawy()); - Draw.color(tile.getTeam().color, Color.WHITE, 0.45f); - Draw.rect(baseTopRegion, tile.drawx(), tile.drawy()); - Draw.color(); - } - - @Override - public void drawLayer(Tile tile){ - TurretEntity entity = tile.entity(); + stats.add(BlockStat.shootRange, range, StatUnit.blocks); + stats.add(BlockStat.inaccuracy, (int) inaccuracy, StatUnit.degrees); + stats.add(BlockStat.reload, 60f / reload, StatUnit.seconds); + stats.add(BlockStat.shots, shots, StatUnit.none); + stats.add(BlockStat.targetsAir, targetAir); + } - tr2.trns(entity.rotation, -entity.recoil); + @Override + public void draw(Tile tile){ + Draw.rect(baseRegion, tile.drawx(), tile.drawy()); + Draw.color(tile.getTeam().color, Color.WHITE, 0.45f); + Draw.rect(baseTopRegion, tile.drawx(), tile.drawy()); + Draw.color(); + } - drawer.accept(tile, entity); + @Override + public void drawLayer(Tile tile){ + TurretEntity entity = tile.entity(); - if(Draw.hasRegion(name + "-heat")){ - heatDrawer.accept(tile, entity); - } + tr2.trns(entity.rotation, -entity.recoil); - Draw.color(); - } + drawer.accept(tile, entity); - @Override + if(heatRegion != null){ + heatDrawer.accept(tile, entity); + } + + Draw.color(); + } + + @Override public TextureRegion[] getBlockIcon(){ - if(blockIcon == null){ - blockIcon = new TextureRegion[]{Draw.region("block-icon-" + name)}; + if(blockIcon == null){ + blockIcon = new TextureRegion[]{Draw.region("block-icon-" + name)}; } return blockIcon; } @Override - public TextureRegion[] getCompactIcon(){ - if(compactIcon == null) { - compactIcon = new TextureRegion[]{iconRegion(Draw.region("block-icon-" + name))}; - } - return compactIcon; - } + public TextureRegion[] getCompactIcon(){ + if(compactIcon == null){ + compactIcon = new TextureRegion[]{iconRegion(Draw.region("block-icon-" + name))}; + } + return compactIcon; + } - @Override - public void drawSelect(Tile tile){ - Draw.color(tile.getTeam().color); - Lines.dashCircle(tile.drawx(), tile.drawy(), range); - Draw.reset(); - } - - @Override - public void drawPlace(int x, int y, int rotation, boolean valid){ - Draw.color(Palette.placing); - Lines.stroke(1f); - Lines.dashCircle(x * tilesize + offset(), y * tilesize + offset(), range); - } + @Override + public void drawSelect(Tile tile){ + Draw.color(tile.getTeam().color); + Lines.dashCircle(tile.drawx(), tile.drawy(), range); + Draw.reset(); + } - @Override - public void update(Tile tile){ - TurretEntity entity = tile.entity(); - - if(entity.target != null && entity.target.isDead()) - entity.target = null; + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + Draw.color(Palette.placing); + Lines.stroke(1f); + Lines.dashCircle(x * tilesize + offset(), y * tilesize + offset(), range); + } - entity.recoil = Mathf.lerpDelta(entity.recoil, 0f, restitution); - entity.heat = Mathf.lerpDelta(entity.heat, 0f, cooldown); - - if(hasAmmo(tile)){ - - if(entity.timer.get(timerTarget, targetInterval)){ - entity.target = Units.getClosestEnemy(tile.getTeam(), - tile.drawx(), tile.drawy(), range, e -> !e.isDead() && (!e.isFlying() || targetAir)); - } - - if(entity.target != null){ - AmmoType type = peekAmmo(tile); - float speed = type.bullet.speed; - if(speed < 0.1f) speed = 9999999f; + @Override + public void update(Tile tile){ + TurretEntity entity = tile.entity(); - Vector2 result = Predict.intercept(entity, entity.target, speed); - if(result.isZero()){ - result.set(entity.target.getX(), entity.target.getY()); - } - - float targetRot = result.sub(tile.drawx(), tile.drawy()).angle(); - - if(Float.isNaN(entity.rotation)){ - entity.rotation = 0; - } + if(entity.target != null && entity.target.isDead()) + entity.target = null; - entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * Timers.delta()); + entity.recoil = Mathf.lerpDelta(entity.recoil, 0f, restitution); + entity.heat = Mathf.lerpDelta(entity.heat, 0f, cooldown); - if(Angles.angleDist(entity.rotation, targetRot) < shootCone){ - updateShooting(tile); - } - } - } - } + if(hasAmmo(tile)){ - /**Consume ammo and return a type.*/ - public AmmoType useAmmo(Tile tile){ + if(entity.timer.get(timerTarget, targetInterval)){ + entity.target = Units.getClosestEnemy(tile.getTeam(), + tile.drawx(), tile.drawy(), range, e -> !e.isDead() && (!e.isFlying() || targetAir)); + } + + if(entity.target != null){ + AmmoType type = peekAmmo(tile); + float speed = type.bullet.speed; + if(speed < 0.1f) speed = 9999999f; + + Vector2 result = Predict.intercept(entity, entity.target, speed); + if(result.isZero()){ + result.set(entity.target.getX(), entity.target.getY()); + } + + float targetRot = result.sub(tile.drawx(), tile.drawy()).angle(); + + if(Float.isNaN(entity.rotation)){ + entity.rotation = 0; + } + + entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * Timers.delta()); + + if(Angles.angleDist(entity.rotation, targetRot) < shootCone){ + updateShooting(tile); + } + } + } + } + + /** + * Consume ammo and return a type. + */ + public AmmoType useAmmo(Tile tile){ TurretEntity entity = tile.entity(); AmmoEntry entry = entity.ammo.peek(); entry.amount -= ammoPerShot; if(entry.amount == 0) entity.ammo.pop(); entity.totalAmmo -= ammoPerShot; - Timers.run(reload/2f, () -> ejectEffects(tile)); + Timers.run(reload / 2f, () -> ejectEffects(tile)); return entry.type; } - /**Get the ammo type that will be returned if useAmmo is called.*/ + /** + * Get the ammo type that will be returned if useAmmo is called. + */ public AmmoType peekAmmo(Tile tile){ TurretEntity entity = tile.entity(); return entity.ammo.peek().type; } - /**Returns whether the turret has ammo.*/ - public boolean hasAmmo(Tile tile){ - TurretEntity entity = tile.entity(); - return entity.ammo.size > 0 && entity.ammo.peek().amount >= ammoPerShot; - } - - protected void updateShooting(Tile tile){ - TurretEntity entity = tile.entity(); + /** + * Returns whether the turret has ammo. + */ + public boolean hasAmmo(Tile tile){ + TurretEntity entity = tile.entity(); + return entity.ammo.size > 0 && entity.ammo.peek().amount >= ammoPerShot; + } - if(entity.reload >= reload) { - AmmoType type = peekAmmo(tile); + protected void updateShooting(Tile tile){ + TurretEntity entity = tile.entity(); + + if(entity.reload >= reload){ + AmmoType type = peekAmmo(tile); shoot(tile, type); entity.reload = 0f; }else{ - entity.reload += Timers.delta() * peekAmmo(tile).reloadMultiplier; - } - } + entity.reload += Timers.delta() * peekAmmo(tile).reloadMultiplier; + } + } - protected void shoot(Tile tile, AmmoType ammo){ - TurretEntity entity = tile.entity(); + protected void shoot(Tile tile, AmmoType ammo){ + TurretEntity entity = tile.entity(); - entity.recoil = recoil; - entity.heat = 1f; + entity.recoil = recoil; + entity.heat = 1f; - AmmoType type = peekAmmo(tile); - useAmmo(tile); + AmmoType type = peekAmmo(tile); + useAmmo(tile); - tr.trns(entity.rotation, size * tilesize / 2); + tr.trns(entity.rotation, size * tilesize / 2); - bullet(tile, ammo.bullet, entity.rotation + Mathf.range(inaccuracy + type.inaccuracy)); + bullet(tile, ammo.bullet, entity.rotation + Mathf.range(inaccuracy + type.inaccuracy)); - effects(tile); - } - - protected void bullet(Tile tile, BulletType type, float angle){ - Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); - } + effects(tile); + } - protected void effects(Tile tile){ - Effect shootEffect = this.shootEffect == Fx.none ? peekAmmo(tile).shootEffect : this.shootEffect; - Effect smokeEffect = this.smokeEffect == Fx.none ? peekAmmo(tile).smokeEffect : this.smokeEffect; + protected void bullet(Tile tile, BulletType type, float angle){ + Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); + } - TurretEntity entity = tile.entity(); + protected void effects(Tile tile){ + Effect shootEffect = this.shootEffect == Fx.none ? peekAmmo(tile).shootEffect : this.shootEffect; + Effect smokeEffect = this.smokeEffect == Fx.none ? peekAmmo(tile).smokeEffect : this.smokeEffect; - Effects.effect(shootEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - Effects.effect(smokeEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + TurretEntity entity = tile.entity(); - if (shootShake > 0) { - Effects.shake(shootShake, shootShake, tile.entity); - } + Effects.effect(shootEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + Effects.effect(smokeEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - entity.recoil = recoil; - } + if(shootShake > 0){ + Effects.shake(shootShake, shootShake, tile.entity); + } - protected void ejectEffects(Tile tile){ - if(!isTurret(tile)) return; - TurretEntity entity = tile.entity(); + entity.recoil = recoil; + } - Effects.effect(ammoUseEffect, tile.drawx() - Angles.trnsx(entity.rotation, ammoEjectBack), - tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation); - } + protected void ejectEffects(Tile tile){ + if(!isTurret(tile)) return; + TurretEntity entity = tile.entity(); - protected boolean isTurret(Tile tile){ - return (tile.entity instanceof TurretEntity); - } + Effects.effect(ammoUseEffect, tile.drawx() - Angles.trnsx(entity.rotation, ammoEjectBack), + tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation); + } - @Override - public TileEntity getEntity(){ - return new TurretEntity(); - } - - public static class TurretEntity extends TileEntity{ - public TileEntity blockTarget; - public Array ammo = new ThreadArray<>(); - public int totalAmmo; - public float reload; - public float rotation = 90; - public float recoil = 0f; - public float heat; - public int shots; - public Unit target; - - @Override - public void write(DataOutputStream stream) throws IOException{ - stream.writeByte(ammo.size); - for(AmmoEntry entry : ammo){ + protected boolean isTurret(Tile tile){ + return (tile.entity instanceof TurretEntity); + } + + @Override + public TileEntity getEntity(){ + return new TurretEntity(); + } + + public static class TurretEntity extends TileEntity{ + public TileEntity blockTarget; + public Array ammo = new ThreadArray<>(); + public int totalAmmo; + public float reload; + public float rotation = 90; + public float recoil = 0f; + public float heat; + public int shots; + public Unit target; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeByte(ammo.size); + for(AmmoEntry entry : ammo){ stream.writeByte(entry.type.id); stream.writeShort(entry.amount); } - } - - @Override - public void read(DataInputStream stream) throws IOException{ - byte amount = stream.readByte(); - for(int i = 0; i < amount; i ++){ - AmmoType type = AmmoType.getByID(stream.readByte()); - short ta = stream.readShort(); - ammo.add(new AmmoEntry(type, ta)); - totalAmmo += ta; + } + + @Override + public void read(DataInputStream stream) throws IOException{ + byte amount = stream.readByte(); + for(int i = 0; i < amount; i++){ + AmmoType type = AmmoType.getByID(stream.readByte()); + short ta = stream.readShort(); + ammo.add(new AmmoEntry(type, ta)); + totalAmmo += ta; } - } - } + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java index 2a366bf0d4..bd5a6bfb8e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java @@ -10,13 +10,13 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class BufferedItemBridge extends ExtendingItemBridge { - protected int timerAccept = timers ++; +public class BufferedItemBridge extends ExtendingItemBridge{ + protected int timerAccept = timers++; protected float speed = 40f; protected int bufferCapacity = 50; - public BufferedItemBridge(String name) { + public BufferedItemBridge(String name){ super(name); hasPower = false; hasItems = true; @@ -26,8 +26,8 @@ public class BufferedItemBridge extends ExtendingItemBridge { public void updateTransport(Tile tile, Tile other){ BufferedItemBridgeEntity entity = tile.entity(); - if(entity.buffer.accepts() && entity.items.totalItems() > 0){ - entity.buffer.accept(entity.items.takeItem()); + if(entity.buffer.accepts() && entity.items.total() > 0){ + entity.buffer.accept(entity.items.take()); } Item item = entity.buffer.poll(); @@ -41,7 +41,7 @@ public class BufferedItemBridge extends ExtendingItemBridge { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new BufferedItemBridgeEntity(); } @@ -49,12 +49,12 @@ public class BufferedItemBridge extends ExtendingItemBridge { ItemBuffer buffer = new ItemBuffer(bufferCapacity, speed); @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ super.write(stream); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ super.read(stream); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Conduit.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Conduit.java index ecaf8d1cea..08f908b2ea 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Conduit.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Conduit.java @@ -5,7 +5,7 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.LiquidBlock; -import io.anuke.mindustry.world.blocks.modules.LiquidModule; +import io.anuke.mindustry.world.modules.LiquidModule; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; @@ -13,40 +13,87 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class Conduit extends LiquidBlock { +public class Conduit extends LiquidBlock{ protected final int timerFlow = timers++; - public Conduit(String name) { + protected TextureRegion[] topRegions = new TextureRegion[7]; + protected TextureRegion[] botRegions = new TextureRegion[7]; + + public Conduit(String name){ super(name); - liquidRegion = "conduit-liquid"; rotate = true; solid = false; } + @Override + public void load(){ + super.load(); + + liquidRegion = Draw.region("conduit-liquid"); + for(int i = 0; i < topRegions.length; i++){ + topRegions[i] = Draw.region(name + "-top-" + i); + botRegions[i] = Draw.region("conduit-bottom-" + i); + } + } + + public void onProximityUpdate(Tile tile){ + ConduitEntity entity = tile.entity(); + entity.blendbits = 0; + + if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){ + entity.blendbits = 3; + }else if(blends(tile, 1) && blends(tile, 2)){ + entity.blendbits = 2; + }else if(blends(tile, 3) && blends(tile, 2)){ + entity.blendbits = 4; + }else if(blends(tile, 0)){ + if(blends(tile, 1) && blends(tile, 3)){ + entity.blendbits = 6; + }else if(blends(tile, 1)){ + entity.blendbits = 5; + }else if(blends(tile, 3)){ + entity.blendbits = 1; + } + }else if(blends(tile, 1)){ + entity.blendbits = 5; + }else if(blends(tile, 3)){ + entity.blendbits = 1; + } + } + + private boolean blends(Tile tile, int direction){ + Tile other = tile.getNearby(Mathf.mod(tile.getRotation() - direction, 4)); + if(other != null) other = other.target(); + + if(other == null || !(other.block().hasLiquids) || !(other.block().outputsLiquid)) return false; + return (tile.getNearby(tile.getRotation()) == other) + || (!other.block().rotate || other.getNearby(other.getRotation()) == tile); + } + @Override public void draw(Tile tile){ ConduitEntity entity = tile.entity(); LiquidModule mod = tile.entity.liquids; + int rotation = tile.getRotation() * 90; - int rotation = rotate ? tile.getRotation() * 90 : 0; + Draw.colorl(0.34f); + Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation); - Draw.rect(name() + "-bottom", tile.drawx(), tile.drawy(), rotation); - - Draw.color(mod.liquid.color); + Draw.color(mod.current().color); Draw.alpha(entity.smoothLiquid); - Draw.rect(liquidRegion, tile.drawx(), tile.drawy(), rotation); + Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation); Draw.color(); - Draw.rect(name() + "-top", tile.drawx(), tile.drawy(), rotation); + Draw.rect(topRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation); } @Override public void update(Tile tile){ ConduitEntity entity = tile.entity(); - entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.amount/liquidCapacity, 0.05f); + entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.total() / liquidCapacity, 0.05f); - if(tile.entity.liquids.amount > 0.001f && tile.entity.timer.get(timerFlow, 1)){ - tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true); + if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){ + tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true, tile.entity.liquids.current()); entity.wakeUp(); }else{ entity.sleep(); @@ -55,30 +102,34 @@ public class Conduit extends LiquidBlock { @Override public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name() + "-bottom"), Draw.region(name() + "-top")}; + if(icon == null){ + icon = new TextureRegion[]{Draw.region("conduit-bottom"), Draw.region(name + "-top-0")}; + } + return icon; } @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ tile.entity.wakeUp(); return super.acceptLiquid(tile, source, liquid, amount) && ((2 + source.relativeTo(tile.x, tile.y)) % 4 != tile.getRotation()); } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new ConduitEntity(); } - public static class ConduitEntity extends TileEntity { + public static class ConduitEntity extends TileEntity{ public float smoothLiquid; + public byte blendbits; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeFloat(smoothLiquid); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ smoothLiquid = stream.readFloat(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java index 47c2de709a..d62e936095 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java @@ -25,410 +25,410 @@ import static io.anuke.mindustry.Vars.itemSize; import static io.anuke.mindustry.Vars.tilesize; public class Conveyor extends Block{ - private static ItemPos drawpos = new ItemPos(); - private static ItemPos pos1 = new ItemPos(); - private static ItemPos pos2 = new ItemPos(); - - private static final float itemSpace = 0.135f * 2.2f; - private static final float offsetScl = 128f*3f; - private static final float minmove = 1f / (Short.MAX_VALUE - 2); - - private final Translator tr1 = new Translator(); - private final Translator tr2 = new Translator(); - private final TextureRegion region1 = new TextureRegion(); - private final TextureRegion region2 = new TextureRegion(); - - protected float speed = 0f; - protected float carryCapacity = 8f; - - protected Conveyor(String name) { - super(name); - rotate = true; - update = true; - layer = Layer.overlay; - group = BlockGroup.transportation; - hasItems = true; - autoSleep = true; - itemCapacity = Math.round(tilesize/ itemSpace); - } - - @Override - public void setBars() {} - - @Override - public void setStats(){ - super.setStats(); - stats.add(BlockStat.itemSpeed, speed * 60, StatUnit.pixelsSecond); - } - - @Override - public void draw(Tile tile){ - ConveyorEntity entity = tile.entity(); - byte rotation = tile.getRotation(); - - GridPoint2 point = Geometry.d4[rotation]; - - int offset = entity.clogHeat <= 0.5f ? (int)((Timers.time()/4f)%8) : 0; - TextureRegion region = Draw.region(name); - - region1.setRegion(region, 0, 0, region.getRegionWidth() - offset, region.getRegionHeight()); - region2.setRegion(region, region.getRegionWidth() - offset, 0, offset, region.getRegionHeight()); - - float x = tile.drawx(), y = tile.drawy(); - - if(offset % 2 == 1){ - if(point.x < 0) x += 0.75f; - if(point.y < 0) - y += 0.5f; - else if(point.y > 0) - y -= 0.5f; - } - - Draw.rect(region1, - x + (point.x * (tilesize/2f - region1.getRegionWidth()/2f)), - y + (point.y * (tilesize/2f - region1.getRegionWidth()/2f)), rotation * 90); - Draw.rect(region2, - x - (point.x * (tilesize/2f - region2.getRegionWidth()/2f)), - y - (point.y * (tilesize/2f - region2.getRegionWidth()/2f)), rotation * 90); - } - - @Override - public boolean isLayer(Tile tile){ - return tile.entity().convey.size > 0; - } - - @Override - public void drawLayer(Tile tile){ - ConveyorEntity entity = tile.entity(); - - byte rotation = tile.getRotation(); - - try { - - for (int i = 0; i < entity.convey.size; i++) { - ItemPos pos = drawpos.set(entity.convey.get(i), ItemPos.drawShorts); - - if (pos.item == null) continue; - - tr1.trns(rotation * 90, tilesize, 0); - tr2.trns(rotation * 90, -tilesize / 2, pos.x * tilesize / 2); - - Draw.rect(pos.item.region, - (int)(tile.x * tilesize + tr1.x * pos.y + tr2.x), - (int)(tile.y * tilesize + tr1.y * pos.y + tr2.y), itemSize, itemSize); - } - - }catch (IndexOutOfBoundsException e){ - Log.err(e); - } - } - - @Override - public void unitOn(Tile tile, Unit unit) { - ConveyorEntity entity = tile.entity(); - - entity.wakeUp(); - - float speed = this.speed * tilesize / 2.3f; - float tx = Geometry.d4[tile.getRotation()].x, ty = Geometry.d4[tile.getRotation()].y; - - float min; - - if(Math.abs(tx) > Math.abs(ty)){ - float rx = tile.worldx() - tx/2f*tilesize; - min = Mathf.clamp((unit.x - rx) * tx / tilesize); - }else{ - float ry = tile.worldy() - ty/2f*tilesize; - min = Mathf.clamp((unit.y - ry) * ty / tilesize); - } - - entity.minCarry = Math.min(entity.minCarry, min); - entity.carrying += unit.getMass(); - - if(entity.convey.size * itemSpace < 0.9f){ - unit.getVelocity().add(tx * speed * Timers.delta(), ty * speed * Timers.delta()); - } - } - - @Override - public synchronized void update(Tile tile){ - - ConveyorEntity entity = tile.entity(); - entity.minitem = 1f; - - int minremove = Integer.MAX_VALUE; - float speed = Math.max(this.speed - (1f - (carryCapacity - entity.carrying) / carryCapacity), 0f); - float totalMoved = 0f; - - for (int i = entity.convey.size - 1; i >= 0; i--) { - long value = entity.convey.get(i); - ItemPos pos = pos1.set(value, ItemPos.updateShorts); - - //..this should never happen, but in case it does, remove it and stop here - if (pos.item == null) { - entity.convey.removeValue(value); - break; - } - - float nextpos = (i == entity.convey.size - 1 ? 100f : pos2.set(entity.convey.get(i + 1), ItemPos.updateShorts).y) - itemSpace; - if (entity.minCarry >= pos.y && entity.minCarry <= nextpos) { - nextpos = entity.minCarry; - } - float maxmove = Math.min(nextpos - pos.y, speed * Timers.delta()); - - if (maxmove > minmove) { - pos.y += maxmove; - pos.x = Mathf.lerpDelta(pos.x, 0, 0.06f); - totalMoved += maxmove; - } else { - pos.x = Mathf.lerpDelta(pos.x, pos.seed / offsetScl, 0.1f); - } - - pos.y = Mathf.clamp(pos.y); - - if (pos.y >= 0.9999f && offloadDir(tile, pos.item)) { - minremove = Math.min(i, minremove); - totalMoved = 1f; - tile.entity.items.removeItem(pos.item, 1); - } else { - value = pos.pack(); - - if (pos.y < entity.minitem) - entity.minitem = pos.y; - entity.convey.set(i, value); - } - } - - if(entity.minitem < itemSpace){ - entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 1f, 0.02f); - }else{ - entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 0f, 1f); - } - - entity.carrying = 0f; - entity.minCarry = 2f; - - if(totalMoved <= 0.0001f){ - entity.sleep(); - } - - if (minremove != Integer.MAX_VALUE) entity.convey.truncate(minremove); - } - - @Override - public boolean isAccessible(){ - return true; - } - - @Override - public synchronized int removeStack(Tile tile, Item item, int amount) { - ConveyorEntity entity = tile.entity(); - entity.wakeUp(); - int removed = 0; - - for(int j = 0; j < amount; j ++) { - for (int i = 0; i < entity.convey.size; i++) { - long val = entity.convey.get(i); - ItemPos pos = pos1.set(val, ItemPos.drawShorts); - if(pos.item == item){ - entity.convey.removeValue(val); - entity.items.removeItem(item, 1); - removed ++; - break; - } - } - } - return removed; - } - - @Override - public void getStackOffset(Item item, Tile tile, Translator trns) { - trns.trns(tile.getRotation()*90 + 180f, tilesize/2f); - } - - @Override - public synchronized int acceptStack(Item item, int amount, Tile tile, Unit source) { - ConveyorEntity entity = tile.entity(); - return entity.minitem > itemSpace ? 1 : 0; - } - - @Override - public synchronized void handleStack(Item item, int amount, Tile tile, Unit source) { - ConveyorEntity entity = tile.entity(); - - long result = ItemPos.packItem(item, 0f, 0f, (byte)Mathf.random(255)); - entity.convey.insert(0, result); - entity.items.addItem(item, 1); - entity.wakeUp(); - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.getRotation()); - float minitem = tile.entity().minitem; - return (((direction == 0) && minitem > itemSpace) || - ((direction %2 == 1) && minitem > 0.52f)) && (source == null || !(source.block().rotate && (source.getRotation() + 2) % 4 == tile.getRotation())); - } - - @Override - public void handleItem(Item item, Tile tile, Tile source){ - byte rotation = tile.getRotation(); - - int ch = Math.abs(source.relativeTo(tile.x, tile.y) - rotation); - int ang = ((source.relativeTo(tile.x, tile.y) - rotation)); - - float pos = ch == 0 ? 0 : ch % 2 == 1 ? 0.5f : 1f; - float y = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0; - - ConveyorEntity entity = tile.entity(); - entity.wakeUp(); - long result = ItemPos.packItem(item, y*0.9f, pos, (byte)Mathf.random(255)); - boolean inserted = false; - - tile.entity.items.addItem(item, 1); - - for(int i = 0; i < entity.convey.size; i ++){ - if(compareItems(result, entity.convey.get(i)) < 0){ - entity.convey.insert(i, result); - inserted = true; - break; - } - } - - //this item must be greater than anything there... - if(!inserted){ - entity.convey.add(result); - } - } - - @Override - public Array getDebugInfo(Tile tile) { - ConveyorEntity entity = tile.entity(); - Array arr = super.getDebugInfo(tile); - arr.addAll(Array.with( - "mincarry", entity.minCarry, - "minitem", entity.minCarry, - "carrying", entity.carrying, - "clogHeat", entity.clogHeat, - "sleeping", entity.isSleeping() - )); - return arr; - } - - @Override - public TileEntity getEntity(){ - return new ConveyorEntity(); - } - - public static class ConveyorEntity extends TileEntity{ - - LongArray convey = new LongArray(); - float minitem = 1; - float carrying; - float minCarry = 2f; - - float clogHeat = 0f; - - @Override - public void write(DataOutputStream stream) throws IOException{ - stream.writeInt(convey.size); - - for(int i = 0; i < convey.size; i ++){ - stream.writeInt(ItemPos.toInt(convey.get(i))); - } - } - - @Override - public void read(DataInputStream stream) throws IOException{ - convey.clear(); - int amount = stream.readInt(); - convey.ensureCapacity(amount); - - for(int i = 0; i < amount; i ++){ - convey.add(ItemPos.toLong(stream.readInt())); - } - } - } - - private static int compareItems(Long a, Long b){ - pos1.set(a, ItemPos.packShorts); - pos2.set(b, ItemPos.packShorts); - return Float.compare(pos1.y, pos2.y); - } - - //Container class. Do not instantiate. - static class ItemPos{ - private static short[] writeShort = new short[4]; - private static byte[] writeByte = new byte[4]; - - private static short[] packShorts = new short[4]; - private static short[] drawShorts = new short[4]; - private static short[] updateShorts = new short[4]; - - Item item; - float x, y; - byte seed; - - private ItemPos(){} - - ItemPos set(long lvalue, short[] values){ - Bits.getShorts(lvalue, values); - - if(values[0] >= Item.all().size || values[0] < 0) - item = null; - else - item = Item.all().get(values[0]); - - x = values[1] / (float)Short.MAX_VALUE; - y = ((float)values[2]) / Short.MAX_VALUE + 1f; - seed = (byte)values[3]; - return this; - } - - long pack(){ - return packItem(item, x, y, seed); - } - - static long packItem(Item item, float x, float y, byte seed){ - short[] shorts = packShorts; - shorts[0] = (short)item.id; - shorts[1] = (short)(x*Short.MAX_VALUE); - shorts[2] = (short)((y - 1f)*Short.MAX_VALUE); - shorts[3] = seed; - return Bits.packLong(shorts); - } - - static int toInt(long value){ - short[] values = Bits.getShorts(value, writeShort); - - short itemid = values[0]; - float x = values[1] / (float)Short.MAX_VALUE; - float y = ((float)values[2]) / Short.MAX_VALUE + 1f; - byte seed = (byte)values[3]; - - byte[] bytes = writeByte; - bytes[0] = (byte)itemid; - bytes[1] = (byte)(x*127); - bytes[2] = (byte)(y*255-128); - bytes[3] = seed; - - return Bits.packInt(bytes); - } - - static long toLong(int value){ - byte[] values = Bits.getBytes(value, writeByte); - - byte itemid = values[0]; - float x = values[1] / 127f; - float y = ((int)values[2] + 128) / 255f; - byte seed = values[3]; - - short[] shorts = writeShort; - shorts[0] = (short)itemid; - shorts[1] = (short)(x*Short.MAX_VALUE); - shorts[2] = (short)((y - 1f)*Short.MAX_VALUE); - shorts[3] = seed; - return Bits.packLong(shorts); - } - } + private static final float itemSpace = 0.135f * 2.2f; + private static final float offsetScl = 128f * 3f; + private static final float minmove = 1f / (Short.MAX_VALUE - 2); + private static ItemPos drawpos = new ItemPos(); + private static ItemPos pos1 = new ItemPos(); + private static ItemPos pos2 = new ItemPos(); + private final Translator tr1 = new Translator(); + private final Translator tr2 = new Translator(); + private final TextureRegion region1 = new TextureRegion(); + private final TextureRegion region2 = new TextureRegion(); + + protected float speed = 0f; + protected float carryCapacity = 8f; + + protected Conveyor(String name){ + super(name); + rotate = true; + update = true; + layer = Layer.overlay; + group = BlockGroup.transportation; + hasItems = true; + autoSleep = true; + itemCapacity = Math.round(tilesize / itemSpace); + } + + private static int compareItems(Long a, Long b){ + pos1.set(a, ItemPos.packShorts); + pos2.set(b, ItemPos.packShorts); + return Float.compare(pos1.y, pos2.y); + } + + @Override + public void setBars(){ + } + + @Override + public void setStats(){ + super.setStats(); + stats.add(BlockStat.itemSpeed, speed * 60, StatUnit.pixelsSecond); + } + + @Override + public void draw(Tile tile){ + ConveyorEntity entity = tile.entity(); + byte rotation = tile.getRotation(); + + GridPoint2 point = Geometry.d4[rotation]; + + int offset = entity.clogHeat <= 0.5f ? (int) ((Timers.time() / 4f) % 8) : 0; + TextureRegion region = Draw.region(name); + + region1.setRegion(region, 0, 0, region.getRegionWidth() - offset, region.getRegionHeight()); + region2.setRegion(region, region.getRegionWidth() - offset, 0, offset, region.getRegionHeight()); + + float x = tile.drawx(), y = tile.drawy(); + + if(offset % 2 == 1){ + if(point.x < 0) x += 0.75f; + if(point.y < 0) + y += 0.5f; + else if(point.y > 0) + y -= 0.5f; + } + + Draw.rect(region1, + x + (point.x * (tilesize / 2f - region1.getRegionWidth() / 2f)), + y + (point.y * (tilesize / 2f - region1.getRegionWidth() / 2f)), rotation * 90); + Draw.rect(region2, + x - (point.x * (tilesize / 2f - region2.getRegionWidth() / 2f)), + y - (point.y * (tilesize / 2f - region2.getRegionWidth() / 2f)), rotation * 90); + } + + @Override + public boolean isLayer(Tile tile){ + return tile.entity().convey.size > 0; + } + + @Override + public void drawLayer(Tile tile){ + ConveyorEntity entity = tile.entity(); + + byte rotation = tile.getRotation(); + + try{ + + for(int i = 0; i < entity.convey.size; i++){ + ItemPos pos = drawpos.set(entity.convey.get(i), ItemPos.drawShorts); + + if(pos.item == null) continue; + + tr1.trns(rotation * 90, tilesize, 0); + tr2.trns(rotation * 90, -tilesize / 2, pos.x * tilesize / 2); + + Draw.rect(pos.item.region, + (int) (tile.x * tilesize + tr1.x * pos.y + tr2.x), + (int) (tile.y * tilesize + tr1.y * pos.y + tr2.y), itemSize, itemSize); + } + + }catch(IndexOutOfBoundsException e){ + Log.err(e); + } + } + + @Override + public void unitOn(Tile tile, Unit unit){ + ConveyorEntity entity = tile.entity(); + + entity.wakeUp(); + + float speed = this.speed * tilesize / 2.3f; + float tx = Geometry.d4[tile.getRotation()].x, ty = Geometry.d4[tile.getRotation()].y; + + float min; + + if(Math.abs(tx) > Math.abs(ty)){ + float rx = tile.worldx() - tx / 2f * tilesize; + min = Mathf.clamp((unit.x - rx) * tx / tilesize); + }else{ + float ry = tile.worldy() - ty / 2f * tilesize; + min = Mathf.clamp((unit.y - ry) * ty / tilesize); + } + + entity.minCarry = Math.min(entity.minCarry, min); + entity.carrying += unit.getMass(); + + if(entity.convey.size * itemSpace < 0.9f){ + unit.getVelocity().add(tx * speed * Timers.delta(), ty * speed * Timers.delta()); + } + } + + @Override + public synchronized void update(Tile tile){ + + ConveyorEntity entity = tile.entity(); + entity.minitem = 1f; + + int minremove = Integer.MAX_VALUE; + float speed = Math.max(this.speed - (1f - (carryCapacity - entity.carrying) / carryCapacity), 0f); + float totalMoved = 0f; + + for(int i = entity.convey.size - 1; i >= 0; i--){ + long value = entity.convey.get(i); + ItemPos pos = pos1.set(value, ItemPos.updateShorts); + + //..this should never happen, but in case it does, remove it and stop here + if(pos.item == null){ + entity.convey.removeValue(value); + break; + } + + float nextpos = (i == entity.convey.size - 1 ? 100f : pos2.set(entity.convey.get(i + 1), ItemPos.updateShorts).y) - itemSpace; + if(entity.minCarry >= pos.y && entity.minCarry <= nextpos){ + nextpos = entity.minCarry; + } + float maxmove = Math.min(nextpos - pos.y, speed * Timers.delta()); + + if(maxmove > minmove){ + pos.y += maxmove; + pos.x = Mathf.lerpDelta(pos.x, 0, 0.06f); + totalMoved += maxmove; + }else{ + pos.x = Mathf.lerpDelta(pos.x, pos.seed / offsetScl, 0.1f); + } + + pos.y = Mathf.clamp(pos.y); + + if(pos.y >= 0.9999f && offloadDir(tile, pos.item)){ + minremove = Math.min(i, minremove); + totalMoved = 1f; + tile.entity.items.remove(pos.item, 1); + }else{ + value = pos.pack(); + + if(pos.y < entity.minitem) + entity.minitem = pos.y; + entity.convey.set(i, value); + } + } + + if(entity.minitem < itemSpace){ + entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 1f, 0.02f); + }else{ + entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 0f, 1f); + } + + entity.carrying = 0f; + entity.minCarry = 2f; + + if(totalMoved <= 0.0001f){ + entity.sleep(); + } + + if(minremove != Integer.MAX_VALUE) entity.convey.truncate(minremove); + } + + @Override + public boolean isAccessible(){ + return true; + } + + @Override + public synchronized int removeStack(Tile tile, Item item, int amount){ + ConveyorEntity entity = tile.entity(); + entity.wakeUp(); + int removed = 0; + + for(int j = 0; j < amount; j++){ + for(int i = 0; i < entity.convey.size; i++){ + long val = entity.convey.get(i); + ItemPos pos = pos1.set(val, ItemPos.drawShorts); + if(pos.item == item){ + entity.convey.removeValue(val); + entity.items.remove(item, 1); + removed++; + break; + } + } + } + return removed; + } + + @Override + public void getStackOffset(Item item, Tile tile, Translator trns){ + trns.trns(tile.getRotation() * 90 + 180f, tilesize / 2f); + } + + @Override + public synchronized int acceptStack(Item item, int amount, Tile tile, Unit source){ + ConveyorEntity entity = tile.entity(); + return entity.minitem > itemSpace ? 1 : 0; + } + + @Override + public synchronized void handleStack(Item item, int amount, Tile tile, Unit source){ + ConveyorEntity entity = tile.entity(); + + long result = ItemPos.packItem(item, 0f, 0f, (byte) Mathf.random(255)); + entity.convey.insert(0, result); + entity.items.add(item, 1); + entity.wakeUp(); + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.getRotation()); + float minitem = tile.entity().minitem; + return (((direction == 0) && minitem > itemSpace) || + ((direction % 2 == 1) && minitem > 0.52f)) && (source == null || !(source.block().rotate && (source.getRotation() + 2) % 4 == tile.getRotation())); + } + + @Override + public void handleItem(Item item, Tile tile, Tile source){ + byte rotation = tile.getRotation(); + + int ch = Math.abs(source.relativeTo(tile.x, tile.y) - rotation); + int ang = ((source.relativeTo(tile.x, tile.y) - rotation)); + + float pos = ch == 0 ? 0 : ch % 2 == 1 ? 0.5f : 1f; + float y = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0; + + ConveyorEntity entity = tile.entity(); + entity.wakeUp(); + long result = ItemPos.packItem(item, y * 0.9f, pos, (byte) Mathf.random(255)); + boolean inserted = false; + + tile.entity.items.add(item, 1); + + for(int i = 0; i < entity.convey.size; i++){ + if(compareItems(result, entity.convey.get(i)) < 0){ + entity.convey.insert(i, result); + inserted = true; + break; + } + } + + //this item must be greater than anything there... + if(!inserted){ + entity.convey.add(result); + } + } + + @Override + public Array getDebugInfo(Tile tile){ + ConveyorEntity entity = tile.entity(); + Array arr = super.getDebugInfo(tile); + arr.addAll(Array.with( + "mincarry", entity.minCarry, + "minitem", entity.minCarry, + "carrying", entity.carrying, + "clogHeat", entity.clogHeat, + "sleeping", entity.isSleeping() + )); + return arr; + } + + @Override + public TileEntity getEntity(){ + return new ConveyorEntity(); + } + + public static class ConveyorEntity extends TileEntity{ + + LongArray convey = new LongArray(); + float minitem = 1; + float carrying; + float minCarry = 2f; + + float clogHeat = 0f; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeInt(convey.size); + + for(int i = 0; i < convey.size; i++){ + stream.writeInt(ItemPos.toInt(convey.get(i))); + } + } + + @Override + public void read(DataInputStream stream) throws IOException{ + convey.clear(); + int amount = stream.readInt(); + convey.ensureCapacity(amount); + + for(int i = 0; i < amount; i++){ + convey.add(ItemPos.toLong(stream.readInt())); + } + } + } + + //Container class. Do not instantiate. + static class ItemPos{ + private static short[] writeShort = new short[4]; + private static byte[] writeByte = new byte[4]; + + private static short[] packShorts = new short[4]; + private static short[] drawShorts = new short[4]; + private static short[] updateShorts = new short[4]; + + Item item; + float x, y; + byte seed; + + private ItemPos(){ + } + + static long packItem(Item item, float x, float y, byte seed){ + short[] shorts = packShorts; + shorts[0] = (short) item.id; + shorts[1] = (short) (x * Short.MAX_VALUE); + shorts[2] = (short) ((y - 1f) * Short.MAX_VALUE); + shorts[3] = seed; + return Bits.packLong(shorts); + } + + static int toInt(long value){ + short[] values = Bits.getShorts(value, writeShort); + + short itemid = values[0]; + float x = values[1] / (float) Short.MAX_VALUE; + float y = ((float) values[2]) / Short.MAX_VALUE + 1f; + byte seed = (byte) values[3]; + + byte[] bytes = writeByte; + bytes[0] = (byte) itemid; + bytes[1] = (byte) (x * 127); + bytes[2] = (byte) (y * 255 - 128); + bytes[3] = seed; + + return Bits.packInt(bytes); + } + + static long toLong(int value){ + byte[] values = Bits.getBytes(value, writeByte); + + byte itemid = values[0]; + float x = values[1] / 127f; + float y = ((int) values[2] + 128) / 255f; + byte seed = values[3]; + + short[] shorts = writeShort; + shorts[0] = (short) itemid; + shorts[1] = (short) (x * Short.MAX_VALUE); + shorts[2] = (short) ((y - 1f) * Short.MAX_VALUE); + shorts[3] = seed; + return Bits.packLong(shorts); + } + + ItemPos set(long lvalue, short[] values){ + Bits.getShorts(lvalue, values); + + if(values[0] >= Item.all().size || values[0] < 0) + item = null; + else + item = Item.all().get(values[0]); + + x = values[1] / (float) Short.MAX_VALUE; + y = ((float) values[2]) / Short.MAX_VALUE + 1f; + seed = (byte) values[3]; + return this; + } + + long pack(){ + return packItem(item, x, y, seed); + } + } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java index f427593c6d..a072628481 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java @@ -10,15 +10,15 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class ExtendingItemBridge extends ItemBridge { +public class ExtendingItemBridge extends ItemBridge{ - public ExtendingItemBridge(String name) { + public ExtendingItemBridge(String name){ super(name); hasItems = true; } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ ItemBridgeEntity entity = tile.entity(); Tile other = world.tile(entity.link); @@ -26,36 +26,36 @@ public class ExtendingItemBridge extends ItemBridge { int i = tile.absoluteRelativeTo(other.x, other.y); - float ex = other.worldx() - tile.worldx() - Geometry.d4[i].x*tilesize/2f, - ey = other.worldy() - tile.worldy() - Geometry.d4[i].y*tilesize/2f; + float ex = other.worldx() - tile.worldx() - Geometry.d4[i].x * tilesize / 2f, + ey = other.worldy() - tile.worldy() - Geometry.d4[i].y * tilesize / 2f; ex *= entity.uptime; ey *= entity.uptime; Lines.stroke(8f); - Lines.line(Draw.region(name + "-bridge"), - tile.worldx() + Geometry.d4[i].x*tilesize/2f, - tile.worldy() + Geometry.d4[i].y*tilesize/2f, + Lines.line(bridgeRegion, + tile.worldx() + Geometry.d4[i].x * tilesize / 2f, + tile.worldy() + Geometry.d4[i].y * tilesize / 2f, tile.worldx() + ex, tile.worldy() + ey, CapStyle.none, 0f); - Draw.rect(name + "-end", tile.drawx(), tile.drawy(), i*90 + 90); - Draw.rect(name + "-end", - tile.worldx() + ex + Geometry.d4[i].x*tilesize/2f, - tile.worldy() + ey + Geometry.d4[i].y*tilesize/2f, i*90 + 270); + Draw.rect(endRegion, tile.drawx(), tile.drawy(), i * 90 + 90); + Draw.rect(endRegion, + tile.worldx() + ex + Geometry.d4[i].x * tilesize / 2f, + tile.worldy() + ey + Geometry.d4[i].y * tilesize / 2f, i * 90 + 270); int dist = Math.max(Math.abs(other.x - tile.x), Math.abs(other.y - tile.y)); - int arrows = (dist)*tilesize/6-1; + int arrows = (dist) * tilesize / 6 - 1; Draw.color(); - for(int a = 0; a < arrows; a ++){ - Draw.alpha(Mathf.absin(a/(float)arrows - entity.time/100f, 0.1f, 1f) * entity.uptime); - Draw.rect(name + "-arrow", - tile.worldx() + Geometry.d4[i].x*(tilesize/2f + a*6f + 2) * entity.uptime, - tile.worldy() + Geometry.d4[i].y*(tilesize/2f + a*6f + 2) * entity.uptime, - i*90f); + for(int a = 0; a < arrows; a++){ + Draw.alpha(Mathf.absin(a / (float) arrows - entity.time / 100f, 0.1f, 1f) * entity.uptime); + Draw.rect(arrowRegion, + tile.worldx() + Geometry.d4[i].x * (tilesize / 2f + a * 6f + 2) * entity.uptime, + tile.worldy() + Geometry.d4[i].y * (tilesize / 2f + a * 6f + 2) * entity.uptime, + i * 90f); } Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java index b07b13c57a..da6c3f30d0 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.world.blocks.distribution; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.IntSet; import com.badlogic.gdx.utils.IntSet.IntSetIterator; @@ -29,16 +30,17 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tilesize; import static io.anuke.mindustry.Vars.world; -public class ItemBridge extends Block { +public class ItemBridge extends Block{ protected static int lastPlaced; protected int timerTransport = timers++; protected int range; - protected float powerUse = 0.05f; protected float transportTime = 2f; protected IntArray removals = new IntArray(); - public ItemBridge(String name) { + protected TextureRegion endRegion, bridgeRegion, arrowRegion; + + public ItemBridge(String name){ super(name); update = true; solid = true; @@ -50,8 +52,35 @@ public class ItemBridge extends Block { hasItems = true; } + @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) + public static void linkItemBridge(Player player, Tile tile, Tile other){ + ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity oe = other.entity(); + entity.link = other.packedPosition(); + oe.incoming.add(tile.packedPosition()); + } + + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) + public static void unlinkItemBridge(Player player, Tile tile, Tile other){ + ItemBridgeEntity entity = tile.entity(); + entity.link = -1; + if(other != null){ + ItemBridgeEntity oe = other.entity(); + oe.incoming.remove(tile.packedPosition()); + } + } + @Override - public void placed(Tile tile) { + public void load(){ + super.load(); + + endRegion = Draw.region(name + "-end"); + bridgeRegion = Draw.region(name + "-bridge"); + arrowRegion = Draw.region(name + "-arrow"); + } + + @Override + public void placed(Tile tile){ Tile last = world.tile(lastPlaced); if(linkValid(tile, last)){ ItemBridgeEntity entity = last.entity(); @@ -63,13 +92,13 @@ public class ItemBridge extends Block { } @Override - public void drawPlace(int x, int y, int rotation, boolean valid) { + public void drawPlace(int x, int y, int rotation, boolean valid){ Lines.stroke(2f); Draw.color(Palette.placing); - for(int i = 0; i < 4; i ++){ + for(int i = 0; i < 4; i++){ Lines.dashLine( - x * tilesize + Geometry.d4[i].x * (tilesize/2f + 2), - y * tilesize + Geometry.d4[i].y * (tilesize/2f + 2), + x * tilesize + Geometry.d4[i].x * (tilesize / 2f + 2), + y * tilesize + Geometry.d4[i].y * (tilesize / 2f + 2), x * tilesize + Geometry.d4[i].x * range * tilesize, y * tilesize + Geometry.d4[i].y * range * tilesize, range); @@ -87,8 +116,8 @@ public class ItemBridge extends Block { Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1f); - for(int i = 1; i <= range; i ++){ - for(int j = 0; j < 4; j ++){ + for(int i = 1; i <= range; i++){ + for(int j = 0; j < 4; j++){ Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i); if(linkValid(tile, other)){ boolean linked = other.packedPosition() == entity.link; @@ -104,7 +133,7 @@ public class ItemBridge extends Block { } @Override - public boolean onConfigureTileTapped(Tile tile, Tile other) { + public boolean onConfigureTileTapped(Tile tile, Tile other){ ItemBridgeEntity entity = tile.entity(); if(linkValid(tile, other)){ @@ -119,11 +148,11 @@ public class ItemBridge extends Block { } @Override - public void update(Tile tile) { + public void update(Tile tile){ ItemBridgeEntity entity = tile.entity(); - entity.time += entity.cycleSpeed*Timers.delta(); - entity.time2 += (entity.cycleSpeed-1f)*Timers.delta(); + entity.time += entity.cycleSpeed * Timers.delta(); + entity.time2 += (entity.cycleSpeed - 1f) * Timers.delta(); removals.clear(); @@ -137,7 +166,7 @@ public class ItemBridge extends Block { } } - for(int j = 0; j < removals.size; j ++) + for(int j = 0; j < removals.size; j++) entity.incoming.remove(removals.get(j)); Tile other = world.tile(entity.link); @@ -145,11 +174,9 @@ public class ItemBridge extends Block { tryDump(tile); entity.uptime = 0f; }else{ - float use = Math.min(powerCapacity, powerUse * Timers.delta()); - if(!hasPower || entity.power.amount >= use){ + if(entity.cons.valid()){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); - if(hasPower) entity.power.amount -= use; }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); } @@ -162,19 +189,19 @@ public class ItemBridge extends Block { ItemBridgeEntity entity = tile.entity(); if(entity.uptime >= 0.5f && entity.timer.get(timerTransport, transportTime)){ - Item item = entity.items.takeItem(); + Item item = entity.items.take(); if(item != null && other.block().acceptItem(item, other, tile)){ other.block().handleItem(item, other, tile); entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); - if(item != null) entity.items.addItem(item, 1); + if(item != null) entity.items.add(item, 1); } } } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ ItemBridgeEntity entity = tile.entity(); Tile other = world.tile(entity.link); @@ -185,40 +212,65 @@ public class ItemBridge extends Block { Draw.color(Color.WHITE, Color.BLACK, Mathf.absin(Timers.time(), 6f, 0.07f)); Draw.alpha(Math.max(entity.uptime, 0.25f)); - Draw.rect(name + "-end", tile.drawx(), tile.drawy(), i*90 + 90); - Draw.rect(name + "-end", other.drawx(), other.drawy(), i*90 + 270); + Draw.rect(endRegion, tile.drawx(), tile.drawy(), i * 90 + 90); + Draw.rect(endRegion, other.drawx(), other.drawy(), i * 90 + 270); Lines.stroke(8f); - Lines.line(Draw.region(name + "-bridge"), + Lines.line(bridgeRegion, tile.worldx(), tile.worldy(), other.worldx(), - other.worldy(), CapStyle.none, -tilesize/2f); + other.worldy(), CapStyle.none, -tilesize / 2f); int dist = Math.max(Math.abs(other.x - tile.x), Math.abs(other.y - tile.y)); - float time = entity.time2/1.7f; - int arrows = (dist)*tilesize/4-2; + float time = entity.time2 / 1.7f; + int arrows = (dist) * tilesize / 4 - 2; Draw.color(); - for(int a = 0; a < arrows; a ++){ - Draw.alpha(Mathf.absin(a/(float)arrows - entity.time/100f, 0.1f, 1f) * entity.uptime); - Draw.rect(name + "-arrow", - tile.worldx() + Geometry.d4[i].x*(tilesize/2f + a*4f + time % 4f), - tile.worldy() + Geometry.d4[i].y*(tilesize/2f + a*4f + time % 4f), - i*90f); + for(int a = 0; a < arrows; a++){ + Draw.alpha(Mathf.absin(a / (float) arrows - entity.time / 100f, 0.1f, 1f) * entity.uptime); + Draw.rect(arrowRegion, + tile.worldx() + Geometry.d4[i].x * (tilesize / 2f + a * 4f + time % 4f), + tile.worldy() + Geometry.d4[i].y * (tilesize / 2f + a * 4f + time % 4f), + i * 90f); } Draw.reset(); } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return tile.entity.items.totalItems() < itemCapacity; + public boolean acceptItem(Item item, Tile tile, Tile source){ + ItemBridgeEntity entity = tile.entity(); + Tile other = world.tile(entity.link); + boolean linked = false; + + if(linkValid(tile, other)){ + linked = true; + int rel = tile.absoluteRelativeTo(other.x, other.y); + int rel2 = tile.relativeTo(source.x, source.y); + + if(rel == rel2) return false; + }else{ + int i = tile.relativeTo(source.x, source.y); + + IntSetIterator it = entity.incoming.iterator(); + + while(it.hasNext){ + int v = it.next(); + int x = v % world.width(); + int y = v / world.width(); + if(tile.absoluteRelativeTo(x, y) == i){ + return false; + } + } + } + + return tile.entity.items.total() < itemCapacity && (linked || source.block() instanceof ItemBridge); } @Override - public boolean canDump(Tile tile, Tile to, Item item) { + public boolean canDump(Tile tile, Tile to, Item item){ ItemBridgeEntity entity = tile.entity(); Tile other = world.tile(entity.link); @@ -245,7 +297,7 @@ public class ItemBridge extends Block { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new ItemBridgeEntity(); } @@ -266,24 +318,6 @@ public class ItemBridge extends Block { return other.block() == this && (!checkDouble || other.entity().link != tile.packedPosition()); } - @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) - public static void linkItemBridge(Player player, Tile tile, Tile other){ - ItemBridgeEntity entity = tile.entity(); - ItemBridgeEntity oe = other.entity(); - entity.link = other.packedPosition(); - oe.incoming.add(tile.packedPosition()); - } - - @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) - public static void unlinkItemBridge(Player player, Tile tile, Tile other){ - ItemBridgeEntity entity = tile.entity(); - entity.link = -1; - if(other != null) { - ItemBridgeEntity oe = other.entity(); - oe.incoming.remove(tile.packedPosition()); - } - } - public static class ItemBridgeEntity extends TileEntity{ public int link = -1; public IntSet incoming = new IntSet(); @@ -293,7 +327,7 @@ public class ItemBridge extends Block { public float cycleSpeed = 1f; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeInt(link); stream.writeFloat(uptime); stream.writeByte(incoming.size); @@ -306,11 +340,11 @@ public class ItemBridge extends Block { } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ link = stream.readInt(); uptime = stream.readFloat(); byte links = stream.readByte(); - for(int i = 0; i < links; i ++){ + for(int i = 0; i < links; i++){ incoming.add(stream.readInt()); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java index d8aa792fe4..f3267a1cf1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java @@ -5,97 +5,98 @@ import com.badlogic.gdx.utils.NumberUtils; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.util.Bits; public class Junction extends Block{ - protected float speed = 26; //frames taken to go through this junction - protected int capacity = 32; + protected float speed = 26; //frames taken to go through this junction + protected int capacity = 32; - public Junction(String name) { - super(name); - update = true; - solid = true; - instantTransfer = true; - group = BlockGroup.transportation; - } + public Junction(String name){ + super(name); + update = true; + solid = true; + instantTransfer = true; + group = BlockGroup.transportation; + } - @Override - public void update(Tile tile){ - JunctionEntity entity = tile.entity(); + @Override + public void update(Tile tile){ + JunctionEntity entity = tile.entity(); - for(int i = 0; i < 2; i ++){ - Buffer buffer = (i == 0 ? entity.bx : entity.by); + for(int i = 0; i < 2; i++){ + Buffer buffer = (i == 0 ? entity.bx : entity.by); - if(buffer.index > 0){ - if(buffer.index > buffer.items.length) buffer.index = buffer.items.length; - long l = buffer.items[0]; - float time = NumberUtils.intBitsToFloat(Bits.getLeftInt(l)); + if(buffer.index > 0){ + if(buffer.index > buffer.items.length) buffer.index = buffer.items.length; + long l = buffer.items[0]; + float time = NumberUtils.intBitsToFloat(Bits.getLeftInt(l)); - if(Timers.time() >= time + speed || Timers.time() < time){ + if(Timers.time() >= time + speed || Timers.time() < time){ - int val = Bits.getRightInt(l); + int val = Bits.getRightInt(l); - Item item = Item.getByID(Bits.getLeftShort(val)); - int direction = Bits.getRightShort(val); - Tile dest = tile.getNearby(direction); + Item item = Item.getByID(Bits.getLeftShort(val)); + int direction = Bits.getRightShort(val); + Tile dest = tile.getNearby(direction); - if(dest == null || !dest.block().acceptItem(item, dest, tile)){ - if(buffer.index > 1 && Bits.getRightShort(Bits.getRightInt(buffer.items[1])) != direction){ - System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1); - buffer.index --; - } - continue; - } + if(dest == null || !dest.block().acceptItem(item, dest, tile)){ + if(buffer.index > 1 && Bits.getRightShort(Bits.getRightInt(buffer.items[1])) != direction){ + System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1); + buffer.index--; + } + continue; + } - dest.block().handleItem(item, dest, tile); - System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1); - buffer.index --; - } - } - } - } + dest.block().handleItem(item, dest, tile); + System.arraycopy(buffer.items, 1, buffer.items, 0, buffer.index - 1); + buffer.index--; + } + } + } + } - @Override - public void handleItem(Item item, Tile tile, Tile source){ - JunctionEntity entity = tile.entity(); - boolean x = tile.x == source.x; - long value = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), Bits.packInt((short)item.id, source.relativeTo(tile.x, tile.y))); - if(x){ - entity.bx.add(value); - }else { - entity.by.add(value); - } - } + @Override + public void handleItem(Item item, Tile tile, Tile source){ + JunctionEntity entity = tile.entity(); + boolean x = tile.x == source.x; + long value = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), Bits.packInt((short) item.id, source.relativeTo(tile.x, tile.y))); + if(x){ + entity.bx.add(value); + }else{ + entity.by.add(value); + } + } - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - JunctionEntity entity = tile.entity(); - boolean x = tile.x == source.x; + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + JunctionEntity entity = tile.entity(); + boolean x = tile.x == source.x; - if(entity == null || entity.bx == null || entity.by == null || (x && entity.bx.full()) || (!x && entity.by.full())) return false; - int dir = source.relativeTo(tile.x, tile.y); - if(dir == -1) return false; - Tile to = tile.getNearby(dir); - return to != null && to.block().acceptItem(item, to, tile); - } + if(entity == null || entity.bx == null || entity.by == null || (x && entity.bx.full()) || (!x && entity.by.full())) + return false; + int dir = source.relativeTo(tile.x, tile.y); + if(dir == -1) return false; + Tile to = tile.getNearby(dir); + return to != null && to.block().acceptItem(item, to, tile); + } - @Override - public TileEntity getEntity() { - return new JunctionEntity(); - } + @Override + public TileEntity getEntity(){ + return new JunctionEntity(); + } - @Override - public Array getDebugInfo(Tile tile){ - JunctionEntity entity = tile.entity(); - Array arr = super.getDebugInfo(tile); - for(int i = 0; i < 4; i ++){ - arr.add("nearby." + i); - arr.add(tile.getNearby(i)); - } + @Override + public Array getDebugInfo(Tile tile){ + JunctionEntity entity = tile.entity(); + Array arr = super.getDebugInfo(tile); + for(int i = 0; i < 4; i++){ + arr.add("nearby." + i); + arr.add(tile.getNearby(i)); + } Consumer write = b -> { for(int i = 0; i < b.index; i++){ @@ -110,32 +111,32 @@ public class Junction extends Block{ } }; - arr.add("buffer.bx"); - arr.add(entity.bx.index); - write.accept(entity.bx); + arr.add("buffer.bx"); + arr.add(entity.bx.index); + write.accept(entity.bx); arr.add("buffer.by"); arr.add(entity.bx.index); - write.accept(entity.by); + write.accept(entity.by); - return arr; - } + return arr; + } - class JunctionEntity extends TileEntity{ - Buffer bx = new Buffer(); - Buffer by = new Buffer(); - } + class JunctionEntity extends TileEntity{ + Buffer bx = new Buffer(); + Buffer by = new Buffer(); + } - class Buffer{ - long[] items = new long[capacity]; - int index; + class Buffer{ + long[] items = new long[capacity]; + int index; - void add(long id){ - if(full()) return; - items[index++] = id; - } + void add(long id){ + if(full()) return; + items[index++] = id; + } - boolean full(){ - return index >= items.length - 1; - } - } + boolean full(){ + return index >= items.length - 1; + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidBridge.java index f014f8574a..55444ca2b0 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidBridge.java @@ -7,37 +7,35 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class LiquidBridge extends ItemBridge { +public class LiquidBridge extends ItemBridge{ - public LiquidBridge(String name) { + public LiquidBridge(String name){ super(name); hasItems = false; hasLiquids = true; + outputsLiquid = true; } @Override - public void update(Tile tile) { + public void update(Tile tile){ ItemBridgeEntity entity = tile.entity(); - entity.time += entity.cycleSpeed* Timers.delta(); - entity.time2 += (entity.cycleSpeed-1f)*Timers.delta(); + entity.time += entity.cycleSpeed * Timers.delta(); + entity.time2 += (entity.cycleSpeed - 1f) * Timers.delta(); Tile other = world.tile(entity.link); - if(!linkValid(tile, other)){ - tryDumpLiquid(tile); + if(!linkValid(tile, other) ){ + tryDumpLiquid(tile, entity.liquids.current()); }else{ - float use = Math.min(powerCapacity, powerUse * Timers.delta()); - - if(entity.power.amount >= use){ + if(entity.cons.valid()){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); - entity.power.amount -= use; }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); } if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other, false) > 0.1f){ + if(tryMoveLiquid(tile, other, false, entity.liquids.current()) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); @@ -47,7 +45,7 @@ public class LiquidBridge extends ItemBridge { } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return false; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidExtendingBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidExtendingBridge.java index 7f3c908359..7be3b85cc5 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidExtendingBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidExtendingBridge.java @@ -7,37 +7,35 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class LiquidExtendingBridge extends ExtendingItemBridge { +public class LiquidExtendingBridge extends ExtendingItemBridge{ - public LiquidExtendingBridge(String name) { + public LiquidExtendingBridge(String name){ super(name); hasItems = false; hasLiquids = true; + outputsLiquid = true; } @Override - public void update(Tile tile) { + public void update(Tile tile){ ItemBridgeEntity entity = tile.entity(); - entity.time += entity.cycleSpeed* Timers.delta(); - entity.time2 += (entity.cycleSpeed-1f)*Timers.delta(); + entity.time += entity.cycleSpeed * Timers.delta(); + entity.time2 += (entity.cycleSpeed - 1f) * Timers.delta(); Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ - tryDumpLiquid(tile); + tryDumpLiquid(tile, entity.liquids.current()); }else{ - float use = Math.min(powerCapacity, powerUse * Timers.delta()); - - if(!hasPower || entity.power.amount >= use){ + if(entity.cons.valid()){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); - if(hasPower) entity.power.amount -= use; }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); } if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other, false) > 0.1f){ + if(tryMoveLiquid(tile, other, false, entity.liquids.current()) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); @@ -47,7 +45,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge { } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return false; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidJunction.java b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidJunction.java index 3d1a47f8c3..4bb6bc1d39 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidJunction.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidJunction.java @@ -6,39 +6,40 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.LiquidBlock; import io.anuke.ucore.graphics.Draw; +//TODO fix public class LiquidJunction extends LiquidBlock{ - public LiquidJunction(String name) { - super(name); - hasLiquids = false; - } - - @Override - public void draw(Tile tile){ - Draw.rect(name(), tile.worldx(), tile.worldy()); - } + public LiquidJunction(String name){ + super(name); + hasLiquids = true; + } - @Override - public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name)}; - } + @Override + public void draw(Tile tile){ + Draw.rect(name(), tile.worldx(), tile.worldy()); + } - @Override - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - int dir = source.relativeTo(tile.x, tile.y); - dir = (dir+4)%4; - Tile to = tile.getNearby(dir); + @Override + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name)}; + } + + @Override + public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + int dir = source.relativeTo(tile.x, tile.y); + dir = (dir + 4) % 4; + Tile to = tile.getNearby(dir); if(to.block().hasLiquids && to.block().acceptLiquid(to, tile, liquid, amount)) to.block().handleLiquid(to, tile, liquid, amount); - } + } - @Override - public boolean acceptLiquid(Tile dest, Tile source, Liquid liquid, float amount){ - int dir = source.relativeTo(dest.x, dest.y); - dir = (dir+4)%4; - Tile to = dest.getNearby(dir); - return to != null && to.block().hasLiquids && - to.block().acceptLiquid(to, dest, liquid, amount); - } + @Override + public boolean acceptLiquid(Tile dest, Tile source, Liquid liquid, float amount){ + int dir = source.relativeTo(dest.x, dest.y); + dir = (dir + 4) % 4; + Tile to = dest.getNearby(dir); + return to != null && to.block().hasLiquids && + to.block().acceptLiquid(to, dest, liquid, amount); + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidRouter.java b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidRouter.java index e2c42784d7..4ca44a549c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidRouter.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/LiquidRouter.java @@ -5,16 +5,16 @@ import io.anuke.mindustry.world.blocks.LiquidBlock; public class LiquidRouter extends LiquidBlock{ - public LiquidRouter(String name) { - super(name); - } - - @Override - public void update(Tile tile){ - - if(tile.entity.liquids.amount > 0){ - tryDumpLiquid(tile); - } - } + public LiquidRouter(String name){ + super(name); + } + + @Override + public void update(Tile tile){ + + if(tile.entity.liquids.total() > 0.01f){ + tryDumpLiquid(tile, tile.entity.liquids.current()); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java index e0a81c997e..ac20aefb83 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java @@ -33,7 +33,7 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class MassDriver extends Block { +public class MassDriver extends Block{ protected float range; protected float rotateSpeed = 0.04f; protected float translation = 7f; @@ -45,7 +45,7 @@ public class MassDriver extends Block { protected Effect recieveEffect = BlockFx.smeltsmoke; protected float shake = 3f; - public MassDriver(String name) { + public MassDriver(String name){ super(name); update = true; solid = true; @@ -56,33 +56,77 @@ public class MassDriver extends Block { hasPower = true; } + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) + public static void linkMassDriver(Player player, Tile tile, int position){ + MassDriverEntity entity = tile.entity(); + + //called in main thread to prevent issues + threads.run(() -> entity.link = position); + } + + @Remote(called = Loc.server, in = In.blocks) + public static void onMassDriverFire(Tile tile, Tile target){ + //just in case the client has invalid data + if(!(tile.entity instanceof MassDriverEntity) || !(target.entity instanceof MassDriverEntity)) return; + + MassDriver driver = (MassDriver) tile.block(); + + MassDriverEntity entity = tile.entity(); + MassDriverEntity other = target.entity(); + + entity.reload = 1f; + + DriverBulletData data = Pooling.obtain(DriverBulletData.class); + data.from = entity; + data.to = other; + for(int i = 0; i < Item.all().size; i++){ + data.items[i] = entity.items.get(Item.getByID(i)); + } + entity.items.clear(); + + float angle = tile.angleTo(target); + + other.isRecieving = true; + Bullet.create(TurretBullets.driverBolt, entity, entity.getTeam(), + tile.drawx() + Angles.trnsx(angle, driver.translation), tile.drawy() + Angles.trnsy(angle, driver.translation), + angle, 1f, data); + + Effects.effect(driver.shootEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), + tile.drawy() + Angles.trnsy(angle, driver.translation), angle); + + Effects.effect(driver.smokeEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), + tile.drawy() + Angles.trnsy(angle, driver.translation), angle); + + Effects.shake(driver.shake, driver.shake, entity); + } + @Override - public void update(Tile tile) { + public void update(Tile tile){ MassDriverEntity entity = tile.entity(); Tile link = world.tile(entity.link); if(entity.isUnloading){ tryDump(tile); - if(entity.items.totalItems() <= 0){ + if(entity.items.total() <= 0){ entity.isUnloading = false; } } if(entity.reload > 0f){ - entity.reload = Mathf.clamp(entity.reload - Timers.delta()/reloadTime); + entity.reload = Mathf.clamp(entity.reload - Timers.delta() / reloadTime); } - if(!entity.isRecieving) { + if(!entity.isRecieving){ - if (entity.waiting.size > 0) { //accepting takes priority over shooting + if(entity.waiting.size > 0){ //accepting takes priority over shooting Tile waiter = entity.waiting.first(); entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(waiter), rotateSpeed); - }else if (tile.entity.items.totalItems() >= minDistribute && - linkValid(tile) && //only fire when at least at half-capacity and power - tile.entity.power.amount >= powerCapacity && - link.block().itemCapacity - link.entity.items.totalItems() >= minDistribute && entity.reload <= 0.0001f) { + }else if(tile.entity.items.total() >= minDistribute && + linkValid(tile) && //only fire when at least at half-capacity and power + tile.entity.power.amount >= powerCapacity && + link.block().itemCapacity - link.entity.items.total() >= minDistribute && entity.reload <= 0.0001f){ MassDriverEntity other = link.entity(); other.waiting.add(tile); @@ -91,8 +135,8 @@ public class MassDriver extends Block { entity.rotation = Mathf.slerpDelta(entity.rotation, target, rotateSpeed); - if (Mathf.angNear(entity.rotation, target, 1f) && - Mathf.angNear(other.rotation, target + 180f, 1f)) { + if(Mathf.angNear(entity.rotation, target, 1f) && + Mathf.angNear(other.rotation, target + 180f, 1f)){ CallBlocks.onMassDriverFire(tile, link); } } @@ -102,7 +146,7 @@ public class MassDriver extends Block { } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ MassDriverEntity entity = tile.entity(); Draw.rect(name + "-turret", @@ -112,7 +156,7 @@ public class MassDriver extends Block { } @Override - public void drawConfigure(Tile tile) { + public void drawConfigure(Tile tile){ super.drawConfigure(tile); MassDriverEntity entity = tile.entity(); @@ -137,7 +181,7 @@ public class MassDriver extends Block { MassDriverEntity entity = tile.entity(); - if(entity.link == other.packedPosition()) { + if(entity.link == other.packedPosition()){ CallBlocks.linkMassDriver(null, tile, -1); return false; }else if(other.block() instanceof MassDriver && other.distanceTo(tile) <= range){ @@ -149,12 +193,12 @@ public class MassDriver extends Block { } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return tile.entity.items.totalItems() < itemCapacity; + public boolean acceptItem(Item item, Tile tile, Tile source){ + return tile.entity.items.total() < itemCapacity; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new MassDriverEntity(); } @@ -166,46 +210,16 @@ public class MassDriver extends Block { return link != null && link.block() instanceof MassDriver && tile.distanceTo(link) <= range; } - @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) - public static void linkMassDriver(Player player, Tile tile, int position){ - MassDriverEntity entity = tile.entity(); + public static class DriverBulletData implements Poolable{ + public MassDriverEntity from, to; + public int[] items = new int[Item.all().size]; - //called in main thread to prevent issues - threads.run(() -> entity.link = position); - } - - @Remote(called = Loc.server, in = In.blocks) - public static void onMassDriverFire(Tile tile, Tile target){ - //just in case the client has invalid data - if(!(tile.entity instanceof MassDriverEntity) || !(target.entity instanceof MassDriverEntity)) return; - - MassDriver driver = (MassDriver)tile.block(); - - MassDriverEntity entity = tile.entity(); - MassDriverEntity other = target.entity(); - - entity.reload = 1f; - - DriverBulletData data = Pooling.obtain(DriverBulletData.class); - data.from = entity; - data.to = other; - System.arraycopy(entity.items.items, 0, data.items, 0, data.items.length); - entity.items.clear(); - - float angle = tile.angleTo(target); - - other.isRecieving = true; - Bullet.create(TurretBullets.driverBolt, entity, entity.getTeam(), - tile.drawx() + Angles.trnsx(angle, driver.translation), tile.drawy() + Angles.trnsy(angle, driver.translation), - angle, 1f, data); - - Effects.effect(driver.shootEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), - tile.drawy() + Angles.trnsy(angle, driver.translation), angle); - - Effects.effect(driver.smokeEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), - tile.drawy() + Angles.trnsy(angle, driver.translation), angle); - - Effects.shake(driver.shake, driver.shake, entity); + @Override + public void reset(){ + from = null; + to = null; + ; + } } public class MassDriverEntity extends TileEntity{ @@ -221,12 +235,12 @@ public class MassDriver extends Block { public float reload = 0f; public void handlePayload(Bullet bullet, DriverBulletData data){ - int totalItems = items.totalItems(); + int totalItems = items.total(); //add all the items possible - for(int i = 0; i < data.items.length; i ++){ + for(int i = 0; i < data.items.length; i++){ int maxAdd = Math.min(data.items[i], itemCapacity - totalItems); - items.items[i] += maxAdd; + items.add(Item.getByID(i), maxAdd); data.items[i] -= maxAdd; totalItems += maxAdd; @@ -236,7 +250,7 @@ public class MassDriver extends Block { } //drop all items remaining on the ground - for(int i = 0; i < data.items.length; i ++){ + for(int i = 0; i < data.items.length; i++){ int amountDropped = Mathf.random(0, data.items[i]); if(amountDropped > 0){ float angle = Mathf.range(180f); @@ -258,24 +272,13 @@ public class MassDriver extends Block { } @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeInt(link); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ link = stream.readInt(); } } - - public static class DriverBulletData implements Poolable{ - public MassDriverEntity from, to; - public int[] items = new int[Item.all().size]; - - @Override - public void reset() { - from = null; - to = null;; - } - } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java index bb1ba9df14..929ffe12ca 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java @@ -1,44 +1,63 @@ package io.anuke.mindustry.world.blocks.distribution; import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Mathf; -public class OverflowGate extends Splitter { +public class OverflowGate extends Splitter{ - public OverflowGate(String name) { + public OverflowGate(String name){ super(name); hasItems = true; + speed = 1f; } @Override - Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ - int dir = source.relativeTo(dest.x, dest.y); - if(dir == -1) return null; - Tile to = dest.getNearby(dir); + public void update(Tile tile){ + SplitterEntity entity = tile.entity(); + if(entity.lastItem != null){ + entity.time += 1f/speed * Timers.delta(); + Tile target = getTileTarget(tile, entity.lastItem, entity.lastInput, false); - if(!(to.block().acceptItem(item, to, dest) && - !(to.block().instantTransfer && source.block().instantTransfer))){ - Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); - Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); - boolean ac = !(a.block().instantTransfer && source.block().instantTransfer) && - a.block().acceptItem(item, a, dest); - boolean bc = !(b.block().instantTransfer && source.block().instantTransfer) && - b.block().acceptItem(item, b, dest); + if(target != null && (entity.time >= 1f)){ + getTileTarget(tile, entity.lastItem, entity.lastInput, true); + target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + entity.items.remove(entity.lastItem, 1); + entity.lastItem = null; + } + } + } + + @Override + Tile getTileTarget(Tile tile, Item item, Tile src, boolean flip){ + int from = tile.relativeTo(src.x, src.y); + if(from == -1) return null; + Tile to = tile.getNearby((from + 2) % 4); + Tile edge = Edges.getFacingEdge(tile, to); + + if(!to.block().acceptItem(item, to, edge) || (to.block() instanceof OverflowGate)){ + Tile a = tile.getNearby(Mathf.mod(from - 1, 4)); + Tile b = tile.getNearby(Mathf.mod(from + 1, 4)); + boolean ac = a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate); + boolean bc = b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate); + + if(!ac && !bc){ + return null; + } if(ac && !bc){ to = a; }else if(bc && !ac){ to = b; }else{ - if(dest.getDump() == 0){ + if(tile.getDump() == 0){ to = a; - if(flip) - dest.setDump((byte)1); + if(flip) tile.setDump((byte) 1); }else{ to = b; - if(flip) - dest.setDump((byte)0); + if(flip) tile.setDump((byte) 0); } } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java index f34158d190..5994982a77 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java @@ -8,48 +8,48 @@ import io.anuke.ucore.core.Timers; public class Router extends Block{ - public Router(String name) { - super(name); - update = true; - solid = true; - itemCapacity = 20; - hasItems = true; - group = BlockGroup.transportation; - autoSleep = true; - } - - @Override - public void update(Tile tile){ - int iterations = Math.max(1, (int) (Timers.delta() + 0.4f)); - boolean moved = tile.entity.items.totalItems() > 0; - - for(int i = 0; i < iterations; i ++) { - if (tile.entity.items.totalItems() > 0) { - tryDump(tile); - moved = true; - } - } - - if(!moved){ - tile.entity.sleep(); - } - } - - @Override - public boolean canDump(Tile tile, Tile to, Item item) { - return !(to.block() instanceof Router) || ((float) to.target().entity.items.totalItems() / to.target().block().itemCapacity) < ((float) tile.entity.items.totalItems() / to.target().block().itemCapacity); + public Router(String name){ + super(name); + update = true; + solid = true; + itemCapacity = 20; + hasItems = true; + group = BlockGroup.transportation; + autoSleep = true; } - @Override - public void handleItem(Item item, Tile tile, Tile source){ - super.handleItem(item, tile, source); - tile.entity.wakeUp(); - } + @Override + public void update(Tile tile){ + int iterations = Math.max(1, (int) (Timers.delta() + 0.4f)); + boolean moved = tile.entity.items.total() > 0; - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - int items = tile.entity.items.totalItems(); - return items < itemCapacity; - } + for(int i = 0; i < iterations; i++){ + if(tile.entity.items.total() > 0){ + tryDump(tile); + moved = true; + } + } + + if(!moved){ + tile.entity.sleep(); + } + } + + @Override + public boolean canDump(Tile tile, Tile to, Item item){ + return !(to.block() instanceof Router) || ((float) to.target().entity.items.total() / to.target().block().itemCapacity) < ((float) tile.entity.items.total() / to.target().block().itemCapacity); + } + + @Override + public void handleItem(Item item, Tile tile, Tile source){ + super.handleItem(item, tile, source); + tile.entity.wakeUp(); + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + int items = tile.entity.items.total(); + return items < itemCapacity; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java index 29d4324f3f..726aa1aadb 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java @@ -21,110 +21,110 @@ import java.io.DataOutputStream; import java.io.IOException; public class Sorter extends Block implements SelectionTrait{ - - public Sorter(String name) { - super(name); - update = true; - solid = true; - instantTransfer = true; - group = BlockGroup.transportation; - configurable = true; - } - - @Override - public void draw(Tile tile){ - super.draw(tile); - //TODO call event for change - - SorterEntity entity = tile.entity(); + public Sorter(String name){ + super(name); + update = true; + solid = true; + instantTransfer = true; + group = BlockGroup.transportation; + configurable = true; + } - Draw.color(entity.sortItem.color); - Draw.rect("blank", tile.worldx(), tile.worldy(), 4f, 4f); - Draw.color(); - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, false); - - return to != null && to.block().acceptItem(item, to, tile); - } - - @Override - public void handleItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, true); + @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) + public static void setSorterItem(Player player, Tile tile, Item item){ + SorterEntity entity = tile.entity(); + entity.sortItem = item; + } - to.block().handleItem(item, to, tile); - } - - Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ - SorterEntity entity = dest.entity(); - - int dir = source.relativeTo(dest.x, dest.y); - if(dir == -1) return null; - Tile to; - - if(item == entity.sortItem){ - to = dest.getNearby(dir); - }else{ - Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); - Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); - boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) && - a.block().acceptItem(item, a, dest); - boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) && - b.block().acceptItem(item, b, dest); - - if(ac && !bc){ - to = a; - }else if(bc && !ac){ - to = b; - }else if(!bc){ - return null; - }else{ - if(dest.getDump() == 0){ - to = a; - if(flip) - dest.setDump((byte)1); - }else{ - to = b; - if(flip) - dest.setDump((byte)0); - } - } - } - - return to; - } - - @Override - public void buildTable(Tile tile, Table table){ - SorterEntity entity = tile.entity(); - buildItemTable(table, () -> entity.sortItem, item -> CallBlocks.setSorterItem(null, tile, item)); - } - - @Override - public TileEntity getEntity(){ - return new SorterEntity(); - } + @Override + public void draw(Tile tile){ + super.draw(tile); - @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) - public static void setSorterItem(Player player, Tile tile, Item item){ - SorterEntity entity = tile.entity(); - entity.sortItem = item; - } + //TODO call event for change - public static class SorterEntity extends TileEntity{ - public Item sortItem = Items.tungsten; - - @Override - public void write(DataOutputStream stream) throws IOException{ - stream.writeByte(sortItem.id); - } - - @Override - public void read(DataInputStream stream) throws IOException{ - sortItem = Item.all().get(stream.readByte()); - } - } + SorterEntity entity = tile.entity(); + + Draw.color(entity.sortItem.color); + Draw.rect("blank", tile.worldx(), tile.worldy(), 4f, 4f); + Draw.color(); + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + Tile to = getTileTarget(item, tile, source, false); + + return to != null && to.block().acceptItem(item, to, tile); + } + + @Override + public void handleItem(Item item, Tile tile, Tile source){ + Tile to = getTileTarget(item, tile, source, true); + + to.block().handleItem(item, to, tile); + } + + Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ + SorterEntity entity = dest.entity(); + + int dir = source.relativeTo(dest.x, dest.y); + if(dir == -1) return null; + Tile to; + + if(item == entity.sortItem){ + to = dest.getNearby(dir); + }else{ + Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); + Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); + boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) && + a.block().acceptItem(item, a, dest); + boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) && + b.block().acceptItem(item, b, dest); + + if(ac && !bc){ + to = a; + }else if(bc && !ac){ + to = b; + }else if(!bc){ + return null; + }else{ + if(dest.getDump() == 0){ + to = a; + if(flip) + dest.setDump((byte) 1); + }else{ + to = b; + if(flip) + dest.setDump((byte) 0); + } + } + } + + return to; + } + + @Override + public void buildTable(Tile tile, Table table){ + SorterEntity entity = tile.entity(); + buildItemTable(table, () -> entity.sortItem, item -> CallBlocks.setSorterItem(null, tile, item)); + } + + @Override + public TileEntity getEntity(){ + return new SorterEntity(); + } + + public static class SorterEntity extends TileEntity{ + public Item sortItem = Items.tungsten; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeByte(sortItem.id); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + sortItem = Item.all().get(stream.readByte()); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java index 54b4a2e3b5..307405e9ca 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java @@ -1,63 +1,98 @@ package io.anuke.mindustry.world.blocks.distribution; +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockGroup; +import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.util.Mathf; +import io.anuke.mindustry.world.meta.BlockGroup; +import io.anuke.ucore.core.Timers; public class Splitter extends Block{ + protected float speed = 9f; public Splitter(String name){ super(name); solid = true; - instantTransfer = true; - destructible = true; + update = true; + hasItems = true; + itemCapacity = 1; group = BlockGroup.transportation; } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, false); + public void setBars(){ + super.setBars(); - return to != null && to.block().acceptItem(item, to, tile); + bars.remove(BarType.inventory); + } + + @Override + public void update(Tile tile){ + SplitterEntity entity = tile.entity(); + if(entity.lastItem != null){ + entity.time += 1f/speed * Timers.delta(); + Tile target = getTileTarget(tile, entity.lastItem, entity.lastInput, false); + + if(target != null && (entity.time >= 1f)){ + getTileTarget(tile, entity.lastItem, entity.lastInput, true); + target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + entity.items.remove(entity.lastItem, 1); + entity.lastItem = null; + } + } + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + SplitterEntity entity = tile.entity(); + + return entity.lastItem == null; } @Override public void handleItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, true); - - to.block().handleItem(item, to, tile); + SplitterEntity entity = tile.entity(); + entity.items.add(item, 1); + entity.lastItem = item; + entity.time = 0f; + entity.lastInput = source; } - Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ - int dir = source.relativeTo(dest.x, dest.y); - if(dir == -1) return null; - Tile to; - - Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); - Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); - boolean ac = !(a.block().instantTransfer && source.block().instantTransfer) && - a.block().acceptItem(item, a, dest); - boolean bc = !(b.block().instantTransfer && source.block().instantTransfer) && - b.block().acceptItem(item, b, dest); - - if(ac && !bc){ - to = a; - }else if(bc && !ac){ - to = b; - }else{ - if(dest.getDump() == 0){ - to = a; - if(flip) - dest.setDump((byte)1); - }else{ - to = b; - if(flip) - dest.setDump((byte)0); + Tile getTileTarget(Tile tile, Item item, Tile from, boolean set){ + Array proximity = tile.entity.proximity(); + int counter = tile.getDump(); + for(int i = 0; i < proximity.size; i++){ + Tile other = proximity.get((i + counter) % proximity.size); + if(tile == from) continue; + if(set) tile.setDump((byte) ((tile.getDump() + 1) % proximity.size)); + if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){ + return other; } } + return null; + } - return to; + @Override + public int removeStack(Tile tile, Item item, int amount){ + SplitterEntity entity = tile.entity(); + int result = super.removeStack(tile, item, amount); + if(result != 0 && item == entity.lastItem){ + entity.lastItem = null; + } + return result; + } + + @Override + public TileEntity getEntity(){ + return new SplitterEntity(); + } + + public class SplitterEntity extends TileEntity{ + Item lastItem; + Tile lastInput; + float time; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/TunnelConduit.java b/core/src/io/anuke/mindustry/world/blocks/distribution/TunnelConduit.java deleted file mode 100644 index 1b636cd22a..0000000000 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/TunnelConduit.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.anuke.mindustry.world.blocks.distribution; - -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import io.anuke.mindustry.type.Liquid; -import io.anuke.mindustry.world.BarType; -import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.blocks.LiquidBlock; -import io.anuke.ucore.graphics.Draw; - -public class TunnelConduit extends LiquidBlock { - protected int maxdist = 3; - protected float speed = 53; - - protected TunnelConduit(String name) { - super(name); - rotate = true; - solid = true; - health = 70; - hasItems = true; - instantTransfer = true; - } - - @Override - public void setBars() { - super.setBars(); - bars.remove(BarType.liquid); - } - - @Override - public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name)}; - } - - @Override - public void draw(Tile tile){ - Draw.rect(name, tile.drawx(), tile.drawy(), tile.getRotation() * 90); - } - - @Override - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - Tile tunnel = getDestTunnel(tile); - if (tunnel == null) return; - Tile to = tunnel.getNearby(tunnel.getRotation()); - if (to == null || !(to.block().hasLiquids)) return; - - if (to.block().acceptLiquid(to, tunnel, liquid, amount)) - to.block().handleLiquid(to, tunnel, liquid, amount); - } - - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - int rot = source.relativeTo(tile.x, tile.y); - if (rot != (tile.getRotation() + 2) % 4) return false; - Tile tunnel = getDestTunnel(tile); - - if (tunnel != null) { - Tile to = tunnel.getNearby(tunnel.getRotation()); - return to != null && (to.block().hasLiquids) && - (to.block()).acceptLiquid(to, tunnel, liquid, amount); - } else { - return false; - } - } - - Tile getDestTunnel(Tile tile) { - Tile dest = tile; - int rel = (tile.getRotation() + 2) % 4; - for (int i = 0; i < maxdist; i++) { - if (dest == null) return null; - dest = dest.getNearby(rel); - if (dest != null && dest.block() instanceof TunnelConduit && dest.getRotation() == rel - && dest.getNearby(rel) != null) { - return dest; - } - } - return null; - } -} diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/WarpGate.java b/core/src/io/anuke/mindustry/world/blocks/distribution/WarpGate.java index 622170e01a..0ed512555b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/WarpGate.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/WarpGate.java @@ -34,138 +34,139 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tilesize; +//TODO implement public class WarpGate extends PowerBlock{ - public static final Color[] colorArray = {Color.ROYAL, Color.ORANGE, Color.SCARLET, Color.LIME, - Color.PURPLE, Color.GOLD, Color.PINK, Color.LIGHT_GRAY}; - public static final int colors = colorArray.length; + public static final Color[] colorArray = {Color.ROYAL, Color.ORANGE, Color.SCARLET, Color.LIME, + Color.PURPLE, Color.GOLD, Color.PINK, Color.LIGHT_GRAY}; + public static final int colors = colorArray.length; + private static ObjectSet[] teleporters = new ObjectSet[colors]; + private static Color color = new Color(); + private static byte lastColor = 0; - protected int timerTeleport = timers++; + static{ + for(int i = 0; i < colors; i++){ + teleporters[i] = new ObjectSet<>(); + } + } - private static ObjectSet[] teleporters = new ObjectSet[colors]; - private static Color color = new Color(); - private static byte lastColor = 0; + protected int timerTeleport = timers++; + protected float warmupTime = 60f; + //time between teleports + protected float teleportMax = 400f; + protected float teleportLiquidUse = 0.3f; + protected Liquid inputLiquid = Liquids.cryofluid; + protected Effect activateEffect = BlockFx.teleportActivate; + protected Effect teleportEffect = BlockFx.teleport; + protected Effect teleportOutEffect = BlockFx.teleportOut; + private Array removal = new Array<>(); + private Array returns = new Array<>(); - private Array removal = new Array<>(); - private Array returns = new Array<>(); + public WarpGate(String name){ + super(name); + update = true; + solid = true; + health = 80; + powerCapacity = 300f; + size = 3; + itemCapacity = 100; + hasLiquids = true; + hasItems = true; + liquidCapacity = 100f; + configurable = true; + } - protected float warmupTime = 60f; - //time between teleports - protected float teleportMax = 400f; - protected float teleportLiquidUse = 0.3f; - protected float liquidUse = 0.1f; - protected float powerUse = 0.3f; - protected Liquid inputLiquid = Liquids.cryofluid; - protected Effect activateEffect = BlockFx.teleportActivate; - protected Effect teleportEffect = BlockFx.teleport; - protected Effect teleportOutEffect = BlockFx.teleportOut; + @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) + public static void setTeleporterColor(Player player, Tile tile, byte color){ + TeleporterEntity entity = tile.entity(); + entity.color = color; + } - static{ - for(int i = 0; i < colors; i ++){ - teleporters[i] = new ObjectSet<>(); - } - } - - public WarpGate(String name) { - super(name); - update = true; - solid = true; - health = 80; - powerCapacity = 300f; - size = 3; - itemCapacity = 100; - hasLiquids = true; - hasItems = true; - liquidCapacity = 100f; - configurable = true; - } + @Override + public void setStats(){ + super.setStats(); + } - @Override - public void setStats(){ - super.setStats(); - } + @Override + public void placed(Tile tile){ + CallBlocks.setTeleporterColor(null, tile, lastColor); + } - @Override - public void placed(Tile tile){ - CallBlocks.setTeleporterColor(null, tile, lastColor); - } - - @Override - public void draw(Tile tile){ - super.draw(tile); + @Override + public void draw(Tile tile){ + super.draw(tile); - TeleporterEntity entity = tile.entity(); - float time = entity.time; - float rad = entity.activeScl; + TeleporterEntity entity = tile.entity(); + float time = entity.time; + float rad = entity.activeScl; - if(entity.liquidLackScl > 0.01f){ - Graphics.setAdditiveBlending(); - Draw.color(1f, 0.3f, 0.3f, 0.4f * entity.liquidLackScl); - Fill.square(tile.drawx(), tile.drawy(), size * tilesize); - Graphics.setNormalBlending(); - } + if(entity.liquidLackScl > 0.01f){ + Graphics.setAdditiveBlending(); + Draw.color(1f, 0.3f, 0.3f, 0.4f * entity.liquidLackScl); + Fill.square(tile.drawx(), tile.drawy(), size * tilesize); + Graphics.setNormalBlending(); + } - Draw.color(getColor(tile, 0)); - Draw.rect(name+"-top", tile.drawx(), tile.drawy()); - Draw.reset(); + Draw.color(getColor(tile, 0)); + Draw.rect(name + "-top", tile.drawx(), tile.drawy()); + Draw.reset(); - if(rad <= 0.0001f) return; + if(rad <= 0.0001f) return; - Draw.color(getColor(tile, 0)); + Draw.color(getColor(tile, 0)); - Fill.circle(tile.drawx(), tile.drawy(), rad*(7f + Mathf.absin(time+55, 8f, 1f))); + Fill.circle(tile.drawx(), tile.drawy(), rad * (7f + Mathf.absin(time + 55, 8f, 1f))); - Draw.color(getColor(tile, -1)); + Draw.color(getColor(tile, -1)); - Fill.circle(tile.drawx(), tile.drawy(), rad*(2f + Mathf.absin(time, 7f, 3f))); + Fill.circle(tile.drawx(), tile.drawy(), rad * (2f + Mathf.absin(time, 7f, 3f))); - for(int i = 0; i < 11; i ++){ - Lines.swirl(tile.drawx(), tile.drawy(), - rad*(2f + i/3f + Mathf.sin(time - i *75, 20f + i, 3f)), - 0.3f + Mathf.sin(time + i *33, 10f + i, 0.1f), - time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f)); - } + for(int i = 0; i < 11; i++){ + Lines.swirl(tile.drawx(), tile.drawy(), + rad * (2f + i / 3f + Mathf.sin(time - i * 75, 20f + i, 3f)), + 0.3f + Mathf.sin(time + i * 33, 10f + i, 0.1f), + time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f)); + } - Draw.color(getColor(tile, 1)); + Draw.color(getColor(tile, 1)); - Lines.stroke(2f); - Lines.circle(tile.drawx(), tile.drawy(), rad*(7f + Mathf.absin(time+55, 8f, 1f))); - Lines.stroke(1f); + Lines.stroke(2f); + Lines.circle(tile.drawx(), tile.drawy(), rad * (7f + Mathf.absin(time + 55, 8f, 1f))); + Lines.stroke(1f); - for(int i = 0; i < 11; i ++){ - Lines.swirl(tile.drawx(), tile.drawy(), - rad*(3f + i/3f + Mathf.sin(time + i *93, 20f + i, 3f)), - 0.2f + Mathf.sin(time + i *33, 10f + i, 0.1f), - time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f)); - } + for(int i = 0; i < 11; i++){ + Lines.swirl(tile.drawx(), tile.drawy(), + rad * (3f + i / 3f + Mathf.sin(time + i * 93, 20f + i, 3f)), + 0.2f + Mathf.sin(time + i * 33, 10f + i, 0.1f), + time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f)); + } - Draw.reset(); - } - - @Override - public void update(Tile tile){ - TeleporterEntity entity = tile.entity(); + Draw.reset(); + } - teleporters[entity.color].add(tile); + @Override + public void update(Tile tile){ + TeleporterEntity entity = tile.entity(); - if(entity.items.totalItems() > 0){ - tryDump(tile); - } + teleporters[entity.color].add(tile); - if(!entity.active){ - entity.activeScl = Mathf.lerpDelta(entity.activeScl, 0f, 0.01f); + if(entity.items.total() > 0){ + tryDump(tile); + } - if(entity.power.amount >= powerCapacity){ - Color resultColor = new Color(); - resultColor.set(getColor(tile, 0)); + if(!entity.active){ + entity.activeScl = Mathf.lerpDelta(entity.activeScl, 0f, 0.01f); - entity.active = true; - entity.power.amount = 0f; - Effects.effect(activateEffect, resultColor, tile.drawx(), tile.drawy()); - } - }else { - entity.activeScl = Mathf.lerpDelta(entity.activeScl, 1f, 0.015f); + if(entity.power.amount >= powerCapacity){ + Color resultColor = new Color(); + resultColor.set(getColor(tile, 0)); - float powerUsed = Math.min(powerCapacity, powerUse * Timers.delta()); + entity.active = true; + entity.power.amount = 0f; + Effects.effect(activateEffect, resultColor, tile.drawx(), tile.drawy()); + } + }else{ + entity.activeScl = Mathf.lerpDelta(entity.activeScl, 1f, 0.015f); + /* if (entity.power.amount >= powerUsed) { entity.power.amount -= powerUsed; @@ -179,38 +180,36 @@ public class WarpGate extends PowerBlock{ catastrophicFailure(tile); } - float liquidUsed = Math.min(liquidCapacity, liquidUse * Timers.delta()); - if (entity.liquids.amount >= liquidUsed) { entity.liquids.amount -= liquidUsed; entity.liquidLackScl = Mathf.lerpDelta(entity.liquidLackScl, 0f, 0.1f); }else{ entity.liquids.amount = 0f; entity.liquidLackScl = Mathf.lerpDelta(entity.liquidLackScl, 1f, 0.1f); - } + }*/ - if(entity.liquidLackScl >= 0.999f){ - catastrophicFailure(tile); - } + if(entity.liquidLackScl >= 0.999f){ + catastrophicFailure(tile); + } - //TODO draw warning info! + //TODO draw warning info! - if (entity.teleporting) { - entity.speedScl = Mathf.lerpDelta(entity.speedScl, 2f, 0.01f); - liquidUsed = Math.min(liquidCapacity, teleportLiquidUse * Timers.delta()); + if(entity.teleporting){ + entity.speedScl = Mathf.lerpDelta(entity.speedScl, 2f, 0.01f); + //liquidUsed = Math.min(liquidCapacity, teleportLiquidUse * Timers.delta()); - if (entity.liquids.amount >= liquidUsed) { - entity.liquids.amount -= liquidUsed; - } else { - catastrophicFailure(tile); - } - } else { - entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.04f); - } + //if (entity.liquids.amount >= liquidUsed) { + // entity.liquids.amount -= liquidUsed; + //} else { + catastrophicFailure(tile); + //} + }else{ + entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.04f); + } - entity.time += Timers.delta() * entity.speedScl; - - if (!entity.teleporting && entity.items.totalItems() >= itemCapacity && entity.power.amount >= powerCapacity - 0.01f - powerUse && + entity.time += Timers.delta() * entity.speedScl; +/* + if (!entity.teleporting && entity.items.total() >= itemCapacity && entity.power.amount >= powerCapacity - 0.01f - powerUse && entity.timer.get(timerTeleport, teleportMax)) { Array testLinks = findLinks(tile); @@ -226,151 +225,145 @@ public class WarpGate extends PowerBlock{ Array links = findLinks(tile); for (Tile other : links) { - int canAccept = itemCapacity - other.entity.items.totalItems(); - int total = entity.items.totalItems(); + int canAccept = itemCapacity - other.entity.items.total(); + int total = entity.items.total(); if (total == 0) break; Effects.effect(teleportOutEffect, resultColor, other.drawx(), other.drawy()); for (int i = 0; i < canAccept && i < total; i++) { - other.entity.items.addItem(entity.items.takeItem(), 1); + other.entity.items.add(entity.items.take(), 1); } } Effects.effect(teleportOutEffect, resultColor, tile.drawx(), tile.drawy()); entity.power.amount = 0f; entity.teleporting = false; }); - } - } - } - - @Override - public void buildTable(Tile tile, Table table){ - TeleporterEntity entity = tile.entity(); + }*/ + } + } - //TODO call event for change + @Override + public void buildTable(Tile tile, Table table){ + TeleporterEntity entity = tile.entity(); - ButtonGroup group = new ButtonGroup<>(); - Table cont = new Table(); + //TODO call event for change - for(int i = 0; i < colors; i ++){ - final int f = i; - ImageButton button = cont.addImageButton("white", "toggle", 24, () -> { - lastColor = (byte)f; - CallBlocks.setTeleporterColor(null, tile, (byte)f); - }).size(34, 38).padBottom(-5.1f).group(group).get(); - button.getStyle().imageUpColor = colorArray[f]; - button.setChecked(entity.color == f); + ButtonGroup group = new ButtonGroup<>(); + Table cont = new Table(); - if(i%4 == 3){ - cont.row(); - } - } + for(int i = 0; i < colors; i++){ + final int f = i; + ImageButton button = cont.addImageButton("white", "toggle", 24, () -> { + lastColor = (byte) f; + CallBlocks.setTeleporterColor(null, tile, (byte) f); + }).size(34, 38).padBottom(-5.1f).group(group).get(); + button.getStyle().imageUpColor = colorArray[f]; + button.setChecked(entity.color == f); - table.add(cont); - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - TeleporterEntity entity = tile.entity(); - return entity.items.totalItems() < itemCapacity; - } - - @Override - public TileEntity getEntity(){ - return new TeleporterEntity(); - } + if(i % 4 == 3){ + cont.row(); + } + } - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid; - } + table.add(cont); + } - @Override - public void onDestroyed(Tile tile) { - super.onDestroyed(tile); + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + TeleporterEntity entity = tile.entity(); + return entity.items.total() < itemCapacity; + } - TeleporterEntity entity = tile.entity(); + @Override + public TileEntity getEntity(){ + return new TeleporterEntity(); + } - if(entity.activeScl < 0.5f) return; + @Override + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid; + } - //TODO catastrophic failure - } + @Override + public void onDestroyed(Tile tile){ + super.onDestroyed(tile); - private void catastrophicFailure(Tile tile){ - tile.entity.damage(tile.entity.health + 1); - //TODO fail gloriously - } + TeleporterEntity entity = tile.entity(); - private Color getColor(Tile tile, int shift){ - TeleporterEntity entity = tile.entity(); + if(entity.activeScl < 0.5f) return; - Color target = colorArray[entity.color]; - float ss = 0.5f; - float bs = 0.2f; + //TODO catastrophic failure + } - return Hue.shift(Hue.multiply(color.set(target), 1, ss), 2, shift * bs + (entity.speedScl - 1f)/3f); - } - - private Array findLinks(Tile tile){ - TeleporterEntity entity = tile.entity(); - - removal.clear(); - returns.clear(); - - for(Tile other : teleporters[entity.color]){ - if(other != tile){ - if(other.block() instanceof WarpGate){ - TeleporterEntity oe = other.entity(); - if(!oe.active) continue; - if(oe.color != entity.color){ - removal.add(other); - }else if(other.entity.items.totalItems() == 0){ - returns.add(other); - } - }else{ - removal.add(other); - } - } - } + private void catastrophicFailure(Tile tile){ + tile.entity.damage(tile.entity.health + 1); + //TODO fail gloriously + } - for(Tile remove : removal) { - teleporters[entity.color].remove(remove); - } - - return returns; - } + private Color getColor(Tile tile, int shift){ + TeleporterEntity entity = tile.entity(); - @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) - public static void setTeleporterColor(Player player, Tile tile, byte color){ - TeleporterEntity entity = tile.entity(); - entity.color = color; - } + Color target = colorArray[entity.color]; + float ss = 0.5f; + float bs = 0.2f; - public static class TeleporterEntity extends TileEntity{ - public byte color = 0; - public boolean teleporting; - public boolean active; - public float activeScl = 0f; - public float speedScl = 1f; - public float powerLackScl, liquidLackScl; - public float time; - - @Override - public void write(DataOutputStream stream) throws IOException{ - stream.writeByte(color); - stream.writeBoolean(active); - stream.writeFloat(activeScl); - stream.writeFloat(speedScl); - stream.writeFloat(powerLackScl); - } - - @Override - public void read(DataInputStream stream) throws IOException{ - color = stream.readByte(); - active = stream.readBoolean(); - activeScl = stream.readFloat(); - speedScl = stream.readFloat(); - powerLackScl = stream.readFloat(); - } - } + return Hue.shift(Hue.multiply(color.set(target), 1, ss), 2, shift * bs + (entity.speedScl - 1f) / 3f); + } + + private Array findLinks(Tile tile){ + TeleporterEntity entity = tile.entity(); + + removal.clear(); + returns.clear(); + + for(Tile other : teleporters[entity.color]){ + if(other != tile){ + if(other.block() instanceof WarpGate){ + TeleporterEntity oe = other.entity(); + if(!oe.active) continue; + if(oe.color != entity.color){ + removal.add(other); + }else if(other.entity.items.total() == 0){ + returns.add(other); + } + }else{ + removal.add(other); + } + } + } + + for(Tile remove : removal){ + teleporters[entity.color].remove(remove); + } + + return returns; + } + + public static class TeleporterEntity extends TileEntity{ + public byte color = 0; + public boolean teleporting; + public boolean active; + public float activeScl = 0f; + public float speedScl = 1f; + public float powerLackScl, liquidLackScl; + public float time; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeByte(color); + stream.writeBoolean(active); + stream.writeFloat(activeScl); + stream.writeFloat(speedScl); + stream.writeFloat(powerLackScl); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + color = stream.readByte(); + active = stream.readBoolean(); + activeScl = stream.readFloat(); + speedScl = stream.readFloat(); + powerLackScl = stream.readFloat(); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/effect/EffectCore.java b/core/src/io/anuke/mindustry/world/blocks/effect/EffectCore.java index adf1a243df..9604d28d8e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/effect/EffectCore.java +++ b/core/src/io/anuke/mindustry/world/blocks/effect/EffectCore.java @@ -11,14 +11,14 @@ import static io.anuke.mindustry.Vars.tilesize; public abstract class EffectCore extends Block{ protected int range = 7; - public EffectCore(String name) { + public EffectCore(String name){ super(name); update = true; solid = true; } @Override - public void drawSelect(Tile tile) { + public void drawSelect(Tile tile){ Draw.color(Palette.accent); Lines.dashCircle(tile.drawx(), tile.drawy(), range * tilesize); Draw.reset(); diff --git a/core/src/io/anuke/mindustry/world/blocks/effect/MendingCore.java b/core/src/io/anuke/mindustry/world/blocks/effect/MendingCore.java index 571cd4112d..897690610a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/effect/MendingCore.java +++ b/core/src/io/anuke/mindustry/world/blocks/effect/MendingCore.java @@ -6,19 +6,21 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; -public class MendingCore extends EffectCore { - /**Mending speed as a percentage of block health, per frame.*/ +public class MendingCore extends EffectCore{ + /** + * Mending speed as a percentage of block health, per frame. + */ protected float mendSpeed = 0.8f; - public MendingCore(String name) { + public MendingCore(String name){ super(name); } @Override - public void update(Tile tile) { + public void update(Tile tile){ - for (int dx = Math.max(-range + tile.x, 0); dx <= Math.min(range + tile.y, world.width() - 1); dx++) { - for (int dy = Math.max(-range + tile.y, 0); dy <= Math.min(range + tile.y, world.height() - 1); dy++) { + for(int dx = Math.max(-range + tile.x, 0); dx <= Math.min(range + tile.y, world.width() - 1); dx++){ + for(int dy = Math.max(-range + tile.y, 0); dy <= Math.min(range + tile.y, world.height() - 1); dy++){ Tile other = world.tile(dx, dy); if(other.entity != null){ diff --git a/core/src/io/anuke/mindustry/world/blocks/logic/LogicBlock.java b/core/src/io/anuke/mindustry/world/blocks/logic/LogicBlock.java index 2e1a11c3b1..ccb78c365c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/logic/LogicBlock.java @@ -4,7 +4,7 @@ import io.anuke.mindustry.world.Block; public class LogicBlock extends Block{ - public LogicBlock(String name) { + public LogicBlock(String name){ super(name); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/modules/InventoryModule.java b/core/src/io/anuke/mindustry/world/blocks/modules/InventoryModule.java deleted file mode 100644 index b989c9b952..0000000000 --- a/core/src/io/anuke/mindustry/world/blocks/modules/InventoryModule.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.anuke.mindustry.world.blocks.modules; - -import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.ItemStack; -import io.anuke.mindustry.world.blocks.BlockModule; - -import java.io.*; -import java.util.Arrays; - -public class InventoryModule extends BlockModule{ - //TODO make private! - public int[] items = new int[Item.all().size]; - - public boolean hasItems(ItemStack[] stacks){ - for(ItemStack stack : stacks){ - if(!hasItem(stack.item, stack.amount)) return false; - } - return true; - } - - public boolean hasItems(ItemStack[] stacks, float amountScaling){ - for(ItemStack stack : stacks){ - if(!hasItem(stack.item, (int)(stack.amount * amountScaling))) return false; - } - return true; - } - - /**Returns true if this entity has at least one of each item in each stack.*/ - public boolean hasAtLeastOneOfItems(ItemStack[] stacks){ - for(ItemStack stack : stacks){ - if(!hasItem(stack.item, 1)) return false; - } - return true; - } - - //TODO optimize! - public int totalItems(){ - int sum = 0; - for(int i = 0; i < items.length; i ++){ - sum += items[i]; - } - return sum; - } - - public Item takeItem(){ - for(int i = 0; i < items.length; i ++){ - if(items[i] > 0){ - items[i] --; - return Item.getByID(i); - } - } - return null; - } - - public int getItem(Item item){ - return items[item.id]; - } - - public boolean hasItem(Item item){ - return getItem(item) > 0; - } - - public boolean hasItem(Item item, int amount){ - return getItem(item) >= amount; - } - - public void addItem(Item item, int amount){ - items[item.id] += amount; - } - - public void removeItem(Item item, int amount){ - items[item.id] -= amount; - } - - public void removeItem(ItemStack stack){ - items[stack.item.id] -= stack.amount; - } - - public void clear(){ - Arrays.fill(items, 0); - } - - @Override - public void write(DataOutput stream) throws IOException { - byte amount = 0; - for(int i = 0; i < items.length; i ++){ - if(items[i] > 0) amount ++; - } - - stream.writeByte(amount); //amount of items - - for(int i = 0; i < items.length; i ++){ - if(items[i] > 0){ - stream.writeByte(i); //item ID - stream.writeInt(items[i]); //item amount - } - } - } - - @Override - public void read(DataInput stream) throws IOException { - byte count = stream.readByte(); - - for(int j = 0; j < count; j ++){ - int itemid = stream.readByte(); - int itemamount = stream.readInt(); - items[itemid] = itemamount; - } - } -} diff --git a/core/src/io/anuke/mindustry/world/blocks/modules/LiquidModule.java b/core/src/io/anuke/mindustry/world/blocks/modules/LiquidModule.java deleted file mode 100644 index 3b26a62247..0000000000 --- a/core/src/io/anuke/mindustry/world/blocks/modules/LiquidModule.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.anuke.mindustry.world.blocks.modules; - -import io.anuke.mindustry.content.Liquids; -import io.anuke.mindustry.type.Liquid; -import io.anuke.mindustry.world.blocks.BlockModule; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public class LiquidModule extends BlockModule { - public float amount; - /**Should never be null.*/ - public Liquid liquid = Liquids.none; - - @Override - public void write(DataOutput stream) throws IOException { - stream.writeByte(liquid.id); - stream.writeFloat(amount); - } - - @Override - public void read(DataInput stream) throws IOException{ - byte id = stream.readByte(); - liquid = Liquid.getByID(id); - amount = stream.readFloat(); - } -} diff --git a/core/src/io/anuke/mindustry/world/blocks/power/BurnerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/BurnerGenerator.java index cee1109845..91051e8a85 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/BurnerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/BurnerGenerator.java @@ -3,19 +3,19 @@ package io.anuke.mindustry.world.blocks.power; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; -public class BurnerGenerator extends ItemLiquidGenerator { +public class BurnerGenerator extends ItemLiquidGenerator{ - public BurnerGenerator(String name) { + public BurnerGenerator(String name){ super(name); } @Override - protected float getLiquidEfficiency(Liquid liquid) { + protected float getLiquidEfficiency(Liquid liquid){ return liquid.flammability; } @Override - protected float getItemEfficiency(Item item) { + protected float getItemEfficiency(Item item){ return item.flammability; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/DecayGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/DecayGenerator.java index f1481bfe23..225efd98c5 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/DecayGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/DecayGenerator.java @@ -2,16 +2,16 @@ package io.anuke.mindustry.world.blocks.power; import io.anuke.mindustry.type.Item; -public class DecayGenerator extends ItemGenerator { +public class DecayGenerator extends ItemGenerator{ - public DecayGenerator(String name) { + public DecayGenerator(String name){ super(name); hasItems = true; hasLiquids = false; } @Override - protected float getItemEfficiency(Item item) { + protected float getItemEfficiency(Item item){ return item.radioactivity; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/FusionReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/FusionReactor.java index f1bed4b378..d31f5a5ed7 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/FusionReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/FusionReactor.java @@ -2,28 +2,25 @@ package io.anuke.mindustry.world.blocks.power; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.production.GenericCrafter.GenericCrafterEntity; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Graphics; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public class FusionReactor extends PowerGenerator { +public class FusionReactor extends PowerGenerator{ protected int plasmas = 4; - protected float powerUsage = 0.5f; - protected float maxPowerProduced = 1.5f; - protected float liquidUsage = 1f; - protected Liquid inputLiquid = Liquids.water; + protected float maxPowerProduced = 2f; protected float warmupSpeed = 0.001f; protected Color plasma1 = Color.valueOf("ffd06b"), plasma2 = Color.valueOf("ff361b"); protected Color ind1 = Color.valueOf("858585"), ind2 = Color.valueOf("fea080"); - public FusionReactor(String name) { + public FusionReactor(String name){ super(name); hasPower = true; hasLiquids = true; @@ -32,16 +29,18 @@ public class FusionReactor extends PowerGenerator { hasItems = true; } + @Override + public void setStats(){ + super.setStats(); + + stats.add(BlockStat.maxPowerGeneration, maxPowerProduced * 60f, StatUnit.powerSecond); + } + @Override public void update(Tile tile){ FusionReactorEntity entity = tile.entity(); - float powerUse = Math.min(powerCapacity, powerUsage * Timers.delta()); - float liquidUse = Math.min(liquidCapacity, liquidUsage * Timers.delta()); - - if(entity.power.amount >= powerUse && entity.liquids.amount >= liquidUse){ - entity.power.amount -= powerUse; - entity.liquids.amount -= liquidUse; + if(entity.cons.valid()){ entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, warmupSpeed); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.01f); @@ -55,17 +54,17 @@ public class FusionReactor extends PowerGenerator { } @Override - public float handleDamage(Tile tile, float amount) { + public float handleDamage(Tile tile, float amount){ FusionReactorEntity entity = tile.entity(); if(entity.warmup < 0.4f) return amount; - float healthFract = tile.entity.health/health; + float healthFract = tile.entity.health / health; //5% chance to explode when hit at <50% HP with a normal bullet if(amount > 5f && healthFract <= 0.5f && Mathf.chance(0.05)){ return health; - //10% chance to explode when hit at <25% HP with a powerful bullet + //10% chance to explode when hit at <25% HP with a powerful bullet }else if(amount > 8f && healthFract <= 0.2f && Mathf.chance(0.1)){ return health; } @@ -74,52 +73,47 @@ public class FusionReactor extends PowerGenerator { } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ FusionReactorEntity entity = tile.entity(); Draw.rect(name + "-bottom", tile.drawx(), tile.drawy()); Graphics.setAdditiveBlending(); - for(int i = 0; i < plasmas; i ++){ - float r = 29f + Mathf.absin(Timers.time(), 2f + i*1f, 5f - i*0.5f); + for(int i = 0; i < plasmas; i++){ + float r = 29f + Mathf.absin(Timers.time(), 2f + i * 1f, 5f - i * 0.5f); - Draw.color(plasma1, plasma2, (float)i/plasmas); - Draw.alpha((0.3f + Mathf.absin(Timers.time(), 2f+i*2f, 0.3f+i*0.05f)) * entity.warmup); - Draw.rect(name + "-plasma-" + i, tile.drawx(), tile.drawy(), r, r, Timers.time()*(12+i*6f) * entity.warmup); + Draw.color(plasma1, plasma2, (float) i / plasmas); + Draw.alpha((0.3f + Mathf.absin(Timers.time(), 2f + i * 2f, 0.3f + i * 0.05f)) * entity.warmup); + Draw.rect(name + "-plasma-" + i, tile.drawx(), tile.drawy(), r, r, Timers.time() * (12 + i * 6f) * entity.warmup); } Draw.color(); Graphics.setNormalBlending(); - Draw.rect(name, tile.drawx(), tile.drawy()); + Draw.rect(region, tile.drawx(), tile.drawy()); Draw.rect(name + "-top", tile.drawx(), tile.drawy()); - Draw.color(ind1, ind2, entity.warmup + Mathf.absin(entity.totalProgress, 3f, entity.warmup*0.5f)); + Draw.color(ind1, ind2, entity.warmup + Mathf.absin(entity.totalProgress, 3f, entity.warmup * 0.5f)); Draw.rect(name + "-light", tile.drawx(), tile.drawy()); Draw.color(); } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ return new TextureRegion[]{Draw.region(name + "-bottom"), Draw.region(name), Draw.region(name + "-top")}; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new FusionReactorEntity(); } @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid; - } - - @Override - public void onDestroyed(Tile tile) { + public void onDestroyed(Tile tile){ super.onDestroyed(tile); FusionReactorEntity entity = tile.entity(); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ItemGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/ItemGenerator.java index 63f551c112..0e5ba6d68a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ItemGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ItemGenerator.java @@ -7,10 +7,10 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.consumers.ConsumeItemFilter; import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; -import io.anuke.mindustry.world.meta.values.ItemFilterValue; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; @@ -23,117 +23,113 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tilesize; -public abstract class ItemGenerator extends PowerGenerator { - protected float minItemEfficiency = 0.2f; - protected float powerOutput; - protected float itemDuration = 70f; - protected Effect generateEffect = BlockFx.generatespark, explodeEffect = - BlockFx.generatespark; - protected Color heatColor = Color.valueOf("ff9b59"); - protected TextureRegion topRegion; +public abstract class ItemGenerator extends PowerGenerator{ + protected float minItemEfficiency = 0.2f; + protected float powerOutput; + protected float itemDuration = 70f; + protected Effect generateEffect = BlockFx.generatespark, explodeEffect = + BlockFx.generatespark; + protected Color heatColor = Color.valueOf("ff9b59"); + protected TextureRegion topRegion; - public ItemGenerator(String name) { - super(name); - itemCapacity = 20; - hasItems = true; - } + public ItemGenerator(String name){ + super(name); + itemCapacity = 20; + hasItems = true; - @Override - public void load() { - super.load(); - topRegion = Draw.region(name + "-top"); - } + consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true); + } - @Override - public void setStats() { - super.setStats(); + @Override + public void load(){ + super.load(); + topRegion = Draw.region(name + "-top"); + } - stats.add(BlockStat.inputItems, new ItemFilterValue(item -> getItemEfficiency(item) >= minItemEfficiency)); - stats.add(BlockStat.maxPowerGeneration, powerOutput * 60f, StatUnit.powerSecond); - } + @Override + public void setStats(){ + super.setStats(); - @Override - public void setBars(){ - super.setBars(); - bars.replace(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity.items.totalItems() / itemCapacity)); - } - - @Override - public void draw(Tile tile){ - super.draw(tile); + stats.add(BlockStat.maxPowerGeneration, powerOutput * 60f, StatUnit.powerSecond); + } - GeneratorEntity entity = tile.entity(); - - if(entity.generateTime > 0){ - Draw.color(heatColor); - float alpha = (entity.items.totalItems() > 0 ? 1f : Mathf.clamp(entity.generateTime)); - alpha = alpha * 0.7f + Mathf.absin(Timers.time(), 12f, 0.3f) * alpha; - Draw.alpha(alpha); - Draw.rect(topRegion, tile.drawx(), tile.drawy()); - Draw.reset(); - } - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - return getItemEfficiency(item) >= minItemEfficiency && tile.entity.items.totalItems() < itemCapacity; - } - - @Override - public void update(Tile tile){ - ItemGeneratorEntity entity = tile.entity(); - - float maxPower = Math.min(powerCapacity - entity.power.amount, powerOutput * Timers.delta()) * entity.efficiency; - float mfract = maxPower/(powerOutput); - - if(entity.generateTime > 0f){ - entity.generateTime -= 1f/itemDuration*mfract; - entity.power.amount += maxPower; - entity.generateTime = Mathf.clamp(entity.generateTime); + @Override + public void setBars(){ + super.setBars(); + bars.replace(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity)); + } - if(Mathf.chance(Timers.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){ - entity.damage(Mathf.random(8f)); - Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize/2f), tile.worldy() + Mathf.range(size * tilesize/2f)); - } - } - - if(entity.generateTime <= 0f && entity.items.totalItems() > 0){ - Effects.effect(generateEffect, tile.worldx() + Mathf.range(size * tilesize/2f), tile.worldy() + Mathf.range(size * tilesize/2f)); - for(int i = 0; i < entity.items.items.length; i ++){ - if(entity.items.items[i] > 0){ - entity.items.items[i] --; - entity.efficiency = getItemEfficiency(Item.getByID(i)); - entity.explosiveness = Item.getByID(i).explosiveness; - break; - } - } - entity.generateTime = 1f; - } - - distributePower(tile); - - } + @Override + public void draw(Tile tile){ + super.draw(tile); - protected abstract float getItemEfficiency(Item item); + GeneratorEntity entity = tile.entity(); - @Override - public TileEntity getEntity() { - return new ItemGeneratorEntity(); - } + if(entity.generateTime > 0){ + Draw.color(heatColor); + float alpha = (entity.items.total() > 0 ? 1f : Mathf.clamp(entity.generateTime)); + alpha = alpha * 0.7f + Mathf.absin(Timers.time(), 12f, 0.3f) * alpha; + Draw.alpha(alpha); + Draw.rect(topRegion, tile.drawx(), tile.drawy()); + Draw.reset(); + } + } - public static class ItemGeneratorEntity extends GeneratorEntity{ - public float efficiency; - public float explosiveness; + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + return getItemEfficiency(item) >= minItemEfficiency && tile.entity.items.total() < itemCapacity; + } - @Override - public void write(DataOutputStream stream) throws IOException { - stream.writeFloat(efficiency); - } + @Override + public void update(Tile tile){ + ItemGeneratorEntity entity = tile.entity(); - @Override - public void read(DataInputStream stream) throws IOException { - efficiency = stream.readFloat(); - } - } + float maxPower = Math.min(powerCapacity - entity.power.amount, powerOutput * Timers.delta()) * entity.efficiency; + float mfract = maxPower / (powerOutput); + + if(entity.generateTime > 0f){ + entity.generateTime -= 1f / itemDuration * mfract; + entity.power.amount += maxPower; + entity.generateTime = Mathf.clamp(entity.generateTime); + + if(Mathf.chance(Timers.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){ + entity.damage(Mathf.random(8f)); + Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f)); + } + } + + if(entity.generateTime <= 0f && entity.items.total() > 0){ + Effects.effect(generateEffect, tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f)); + Item item = entity.items.take(); + entity.efficiency = getItemEfficiency(item); + entity.explosiveness = item.explosiveness; + entity.generateTime = 1f; + } + + distributePower(tile); + + } + + protected abstract float getItemEfficiency(Item item); + + @Override + public TileEntity getEntity(){ + return new ItemGeneratorEntity(); + } + + public static class ItemGeneratorEntity extends GeneratorEntity{ + public float efficiency; + public float explosiveness; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeFloat(efficiency); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + efficiency = stream.readFloat(); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java index 82e06c95d1..60fc48d267 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -4,8 +4,7 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.values.LiquidFilterValue; +import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; @@ -13,67 +12,67 @@ import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.tilesize; -public abstract class ItemLiquidGenerator extends ItemGenerator { +public abstract class ItemLiquidGenerator extends ItemGenerator{ protected float minLiquidEfficiency = 0.2f; protected float powerPerLiquid = 0.13f; - /**Maximum liquid used per frame.*/ + /** + * Maximum liquid used per frame. + */ protected float maxLiquidGenerate = 0.4f; - public ItemLiquidGenerator(String name) { + public ItemLiquidGenerator(String name){ super(name); hasLiquids = true; liquidCapacity = 10f; - } - @Override - public void setStats() { - super.setStats(); - - stats.add(BlockStat.inputLiquid, new LiquidFilterValue(item -> getLiquidEfficiency(item) >= minLiquidEfficiency)); + consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true); } @Override public void update(Tile tile){ ItemGeneratorEntity entity = tile.entity(); - //liquid takes priority over solids - if(entity.liquids.amount >= 0.001f){ - float powerPerLiquid = getLiquidEfficiency(entity.liquids.liquid)*this.powerPerLiquid; - float used = Math.min(entity.liquids.amount, maxLiquidGenerate * Timers.delta()); - used = Math.min(used, (powerCapacity - entity.power.amount)/powerPerLiquid); + Liquid liquid = null; + for(Liquid other : Liquid.all()){ + if(entity.liquids.get(other) >= 0.001f && getLiquidEfficiency(other) >= minLiquidEfficiency){ + liquid = other; + break; + } + } - entity.liquids.amount -= used; + //liquid takes priority over solids + if(liquid != null && entity.liquids.get(liquid) >= 0.001f && entity.cons.valid()){ + float powerPerLiquid = getLiquidEfficiency(liquid) * this.powerPerLiquid; + float used = Math.min(entity.liquids.get(liquid), maxLiquidGenerate * Timers.delta()); + used = Math.min(used, (powerCapacity - entity.power.amount) / powerPerLiquid); + + entity.liquids.remove(liquid, used); entity.power.amount += used * powerPerLiquid; if(used > 0.001f && Mathf.chance(0.05 * Timers.delta())){ Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); } - }else { + }else if(entity.cons.valid()){ float maxPower = Math.min(powerCapacity - entity.power.amount, powerOutput * Timers.delta()) * entity.efficiency; float mfract = maxPower / (powerOutput); - if (entity.generateTime > 0f) { + if(entity.generateTime > 0f){ entity.generateTime -= 1f / itemDuration * mfract; entity.power.amount += maxPower; entity.generateTime = Mathf.clamp(entity.generateTime); if(Mathf.chance(Timers.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){ entity.damage(Mathf.random(8f)); - Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize/2f), tile.worldy() + Mathf.range(size * tilesize/2f)); + Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f)); } } - if (entity.generateTime <= 0f && entity.items.totalItems() > 0) { + if(entity.generateTime <= 0f && entity.items.total() > 0){ Effects.effect(generateEffect, tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f)); - for (int i = 0; i < entity.items.items.length; i++) { - if (entity.items.items[i] > 0) { - entity.items.items[i]--; - entity.efficiency = getItemEfficiency(Item.getByID(i)); - entity.explosiveness = Item.getByID(i).explosiveness; - break; - } - } + Item item = entity.items.take(); + entity.efficiency = getItemEfficiency(item); + entity.explosiveness = item.explosiveness; entity.generateTime = 1f; } } @@ -87,20 +86,20 @@ public abstract class ItemLiquidGenerator extends ItemGenerator { TileEntity entity = tile.entity(); - Draw.color(entity.liquids.liquid.color); - Draw.alpha(entity.liquids.amount / liquidCapacity); + Draw.color(entity.liquids.current().color); + Draw.alpha(entity.liquids.currentAmount() / liquidCapacity); drawLiquidCenter(tile); Draw.color(); } + @Override + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + return getLiquidEfficiency(liquid) >= minLiquidEfficiency && tile.entity.liquids.get(liquid) < liquidCapacity; + } + public void drawLiquidCenter(Tile tile){ Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2); } - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return getLiquidEfficiency(liquid) >= minLiquidEfficiency && super.acceptLiquid(tile, source, liquid, amount); - } - protected abstract float getLiquidEfficiency(Liquid liquid); } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java index ff276b057e..b33f2c82d3 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java @@ -5,82 +5,80 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.power.ItemGenerator.ItemGeneratorEntity; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.values.LiquidFilterValue; +import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public abstract class LiquidGenerator extends PowerGenerator { - protected float minEfficiency = 0.2f; - protected float powerPerLiquid = 0.13f; - /**Maximum liquid used per frame.*/ - protected float maxLiquidGenerate = 0.4f; - protected Effect generateEffect = BlockFx.generatespark; +public abstract class LiquidGenerator extends PowerGenerator{ + protected float minEfficiency = 0.2f; + protected float powerPerLiquid = 0.13f; + /** + * Maximum liquid used per frame. + */ + protected float maxLiquidGenerate = 0.4f; + protected Effect generateEffect = BlockFx.generatespark; - public LiquidGenerator(String name) { - super(name); - liquidCapacity = 30f; - hasLiquids = true; - } + public LiquidGenerator(String name){ + super(name); + liquidCapacity = 30f; + hasLiquids = true; - @Override - public void setStats() { - super.setStats(); + consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, 0.001f)).update(false); + } - stats.add(BlockStat.inputLiquid, new LiquidFilterValue(item -> getEfficiency(item) >= minEfficiency)); - } + @Override + public void draw(Tile tile){ + super.draw(tile); - @Override - public void draw(Tile tile){ - super.draw(tile); + TileEntity entity = tile.entity(); - TileEntity entity = tile.entity(); - - Draw.color(entity.liquids.liquid.color); - Draw.alpha(entity.liquids.amount / liquidCapacity); - drawLiquidCenter(tile); - Draw.color(); - } - - public void drawLiquidCenter(Tile tile){ - Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2); - } - - @Override - public void update(Tile tile){ - TileEntity entity = tile.entity(); - - if(entity.liquids.amount > 0){ - float powerPerLiquid = getEfficiency(entity.liquids.liquid)*this.powerPerLiquid; - float used = Math.min(entity.liquids.amount, maxLiquidGenerate * Timers.delta()); - used = Math.min(used, (powerCapacity - entity.power.amount)/powerPerLiquid); - - entity.liquids.amount -= used; - entity.power.amount += used * powerPerLiquid; - - if(used > 0.001f && Mathf.chance(0.05 * Timers.delta())){ - Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); - } - } - - distributePower(tile); - } - - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return getEfficiency(liquid) >= minEfficiency && super.acceptLiquid(tile, source, liquid, amount); - } + Draw.color(entity.liquids.current().color); + Draw.alpha(entity.liquids.total() / liquidCapacity); + drawLiquidCenter(tile); + Draw.color(); + } - @Override - public TileEntity getEntity() { - return new ItemGeneratorEntity(); - } + public void drawLiquidCenter(Tile tile){ + Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2); + } - /**Returns an efficiency value for the specified liquid. - * Greater efficiency means more power generation. - * If a liquid's efficiency is below {@link #minEfficiency}, it is not accepted.*/ - protected abstract float getEfficiency(Liquid liquid); + @Override + public void update(Tile tile){ + TileEntity entity = tile.entity(); + + if(entity.liquids.get(entity.liquids.current()) >= 0.001f){ + float powerPerLiquid = getEfficiency(entity.liquids.current()) * this.powerPerLiquid; + float used = Math.min(entity.liquids.currentAmount(), maxLiquidGenerate * Timers.delta()); + used = Math.min(used, (powerCapacity - entity.power.amount) / powerPerLiquid); + + entity.liquids.remove(entity.liquids.current(), used); + entity.power.amount += used * powerPerLiquid; + + if(used > 0.001f && Mathf.chance(0.05 * Timers.delta())){ + Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); + } + } + + distributePower(tile); + } + + @Override + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + return getEfficiency(liquid) >= minEfficiency && super.acceptLiquid(tile, source, liquid, amount); + } + + @Override + public TileEntity getEntity(){ + return new ItemGeneratorEntity(); + } + + /** + * Returns an efficiency value for the specified liquid. + * Greater efficiency means more power generation. + * If a liquid's efficiency is below {@link #minEfficiency}, it is not accepted. + */ + protected abstract float getEfficiency(Liquid liquid); } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java index d591bea4f9..3990a6c731 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java @@ -2,14 +2,14 @@ package io.anuke.mindustry.world.blocks.power; import io.anuke.mindustry.type.Liquid; -public class LiquidHeatGenerator extends LiquidGenerator { +public class LiquidHeatGenerator extends LiquidGenerator{ - public LiquidHeatGenerator(String name) { + public LiquidHeatGenerator(String name){ super(name); } @Override protected float getEfficiency(Liquid liquid){ - return liquid.temperature-0.5f; + return liquid.temperature - 0.5f; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java index 55e6ce750c..9759b2e63e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java @@ -1,12 +1,12 @@ package io.anuke.mindustry.world.blocks.power; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.content.Items; import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.content.fx.ExplosionFx; import io.anuke.mindustry.entities.Damage; import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Tile; @@ -26,183 +26,193 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.tilesize; -public class NuclearReactor extends PowerGenerator { - protected final int timerFuel = timers++; +//TODO refactor to use consumers +public class NuclearReactor extends PowerGenerator{ + protected final int timerFuel = timers++; - protected final Translator tr = new Translator(); + protected final Translator tr = new Translator(); - protected Item generateItem; - protected Color coolColor = new Color(1, 1, 1, 0f); - protected Color hotColor = Color.valueOf("ff9575a3"); - protected int fuelUseTime = 120; //time to consume 1 fuel - protected float powerMultiplier = 0.45f; //power per frame, depends on full capacity - protected float heating = 0.009f; //heating per frame - protected float coolantPower = 0.015f; //how much heat decreases per coolant unit - protected float smokeThreshold = 0.3f; //threshold at which block starts smoking - protected float maxLiquidUse = 1f; //max liquid use per frame - protected int explosionRadius = 19; - protected int explosionDamage = 135; - protected float flashThreshold = 0.46f; //heat threshold at which the lights start flashing + protected Color coolColor = new Color(1, 1, 1, 0f); + protected Color hotColor = Color.valueOf("ff9575a3"); + protected int fuelUseTime = 120; //time to consume 1 fuel + protected float powerMultiplier = 0.45f; //power per frame, depends on full capacity + protected float heating = 0.013f; //heating per frame + protected float coolantPower = 0.015f; //how much heat decreases per coolant unit + protected float smokeThreshold = 0.3f; //threshold at which block starts smoking + protected float maxLiquidUse = 2f; //max liquid use per frame + protected int explosionRadius = 19; + protected int explosionDamage = 135; + protected float flashThreshold = 0.46f; //heat threshold at which the lights start flashing - public NuclearReactor(String name) { - super(name); - generateItem = Items.thorium; - itemCapacity = 30; - liquidCapacity = 50; - powerCapacity = 80f; - hasItems = true; - hasLiquids = true; - } + protected TextureRegion topRegion, lightsRegion; - @Override - public void setBars(){ - super.setBars(); - bars.replace(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity.items.getItem(generateItem) / itemCapacity)); - bars.add(new BlockBar(BarType.heat, true, tile -> tile.entity().heat)); - } + public NuclearReactor(String name){ + super(name); + itemCapacity = 30; + liquidCapacity = 50; + powerCapacity = 80f; + hasItems = true; + hasLiquids = true; - @Override - public void setStats(){ - super.setStats(); - stats.add(BlockStat.inputItem, generateItem); - stats.add(BlockStat.inputLiquid, new LiquidFilterValue(liquid -> liquid.temperature <= 0.5f)); - stats.add(BlockStat.maxPowerGeneration, powerMultiplier*60f, StatUnit.powerSecond); - } - - @Override - public void update(Tile tile){ - NuclearReactorEntity entity = tile.entity(); - - int fuel = entity.items.getItem(generateItem); - float fullness = (float)fuel / itemCapacity; - - if(fuel > 0){ - entity.heat += fullness * heating * Math.min(Timers.delta(), 4f); - entity.power.amount += powerMultiplier * fullness * Timers.delta(); - entity.power.amount = Mathf.clamp(entity.power.amount, 0f, powerCapacity); - if(entity.timer.get(timerFuel, fuelUseTime)){ - entity.items.removeItem(generateItem, 1); - } - } - - if(entity.liquids.amount > 0){ + consumes.item(Items.thorium); + } - if(entity.liquids.liquid.temperature <= 0.5f){ //is coolant - float pow = coolantPower * entity.liquids.liquid.heatCapacity; //heat depleted per unit of liquid - float maxUsed = Math.min(Math.min(entity.liquids.amount, entity.heat / pow), maxLiquidUse * Timers.delta()); //max that can be cooled in terms of liquid - entity.heat -= maxUsed * pow; - entity.liquids.amount -= maxUsed; - }else{ //is heater - float heat = coolantPower * entity.liquids.liquid.heatCapacity / 4f; //heat created per unit of liquid - float maxUsed = Math.min(Math.min(entity.liquids.amount, (1f - entity.heat) / heat), maxLiquidUse * Timers.delta()); //max liquid used - entity.heat += maxUsed * heat; - entity.liquids.amount -= maxUsed; - } - } - - if(entity.heat > smokeThreshold){ - float smoke = 1.0f + (entity.heat - smokeThreshold) / (1f - smokeThreshold); //ranges from 1.0 to 2.0 - if(Mathf.chance(smoke / 20.0 * Timers.delta())){ - Effects.effect(BlockFx.reactorsmoke, tile.worldx() + Mathf.range(size * tilesize / 2f), - tile.worldy() + Mathf.random(size * tilesize / 2f)); - } - } + @Override + public void load(){ + super.load(); - entity.heat = Mathf.clamp(entity.heat); - - if(entity.heat >= 1f){ - entity.damage((int)entity.health); - }else{ - distributePower(tile); - } - } - - @Override - public void onDestroyed(Tile tile){ - super.onDestroyed(tile); - - NuclearReactorEntity entity = tile.entity(); - - int fuel = entity.items.getItem(generateItem); - - if(fuel < 5 && entity.heat < 0.5f) return; - - Effects.shake(6f, 16f, tile.worldx(), tile.worldy()); - Effects.effect(ExplosionFx.nuclearShockwave, tile.worldx(), tile.worldy()); - for(int i = 0; i < 6; i ++){ - Timers.run(Mathf.random(40), () -> { - Effects.effect(BlockFx.nuclearcloud, tile.worldx(), tile.worldy()); - }); - } - - Damage.damage(tile.worldx(), tile.worldy(), explosionRadius * tilesize, explosionDamage * 4); - - - for(int i = 0; i < 20; i ++){ - Timers.run(Mathf.random(50), ()->{ - tr.rnd(Mathf.random(40f)); - Effects.effect(ExplosionFx.explosion, tr.x + tile.worldx(), tr.y + tile.worldy()); - }); - } - - for(int i = 0; i < 70; i ++){ - Timers.run(Mathf.random(80), ()->{ - tr.rnd(Mathf.random(120f)); - Effects.effect(BlockFx.nuclearsmoke, tr.x + tile.worldx(), tr.y + tile.worldy()); - }); - } - } + topRegion = Draw.region(name + "-center"); + lightsRegion = Draw.region(name + "-lights"); + } - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - return item == generateItem && tile.entity.items.getItem(generateItem) < itemCapacity; - } + @Override + public void setBars(){ + super.setBars(); + bars.replace(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.get(consumes.item()) / itemCapacity)); + bars.add(new BlockBar(BarType.heat, true, tile -> tile.entity().heat)); + } - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return tile.entity.liquids.amount + amount < liquidCapacity - && (tile.entity.liquids.liquid == liquid || tile.entity.liquids.amount <= 0.001f); - } + @Override + public void setStats(){ + super.setStats(); + stats.add(BlockStat.inputLiquid, new LiquidFilterValue(liquid -> liquid.temperature <= 0.5f)); + stats.add(BlockStat.maxPowerGeneration, powerMultiplier * 60f, StatUnit.powerSecond); + } - @Override - public void draw(Tile tile){ - super.draw(tile); - - NuclearReactorEntity entity = tile.entity(); - - Draw.color(coolColor, hotColor, entity.heat); - Draw.rect("white", tile.drawx(), tile.drawy(), size * tilesize, size * tilesize); - - if(entity.heat > flashThreshold){ - float flash = 1f + ((entity.heat - flashThreshold) / (1f - flashThreshold)) * 5.4f; - entity.flash += flash * Timers.delta(); - Draw.color(Color.RED, Color.YELLOW, Mathf.absin(entity.flash, 9f, 1f)); - Draw.alpha(0.6f); - Draw.rect(name + "-lights", tile.drawx(), tile.drawy()); - } - - Draw.reset(); - } - - @Override - public TileEntity getEntity(){ - return new NuclearReactorEntity(); - } - - public static class NuclearReactorEntity extends GeneratorEntity { - public float heat; - public float flash; - - @Override - public void write(DataOutputStream stream) throws IOException{ - super.write(stream); - stream.writeFloat(heat); - } - - @Override - public void read(DataInputStream stream) throws IOException{ - super.read(stream); - heat = stream.readFloat(); - } - } + @Override + public void update(Tile tile){ + NuclearReactorEntity entity = tile.entity(); + + int fuel = entity.items.get(consumes.item()); + float fullness = (float) fuel / itemCapacity; + + if(fuel > 0){ + entity.heat += fullness * heating * Math.min(Timers.delta(), 4f); + entity.power.amount += powerMultiplier * fullness * Timers.delta(); + entity.power.amount = Mathf.clamp(entity.power.amount, 0f, powerCapacity); + if(entity.timer.get(timerFuel, fuelUseTime)){ + entity.items.remove(consumes.item(), 1); + } + } + + if(entity.liquids.total() > 0){ + Liquid liquid = entity.liquids.current(); + + if(liquid.temperature <= 0.5f){ //is coolant + float pow = coolantPower * (liquid.heatCapacity + 0.5f / liquid.temperature); //heat depleted per unit of liquid + float maxUsed = Math.min(Math.min(entity.liquids.get(liquid), entity.heat / pow), maxLiquidUse * Timers.delta()); //max that can be cooled in terms of liquid + entity.heat -= maxUsed * pow; + entity.liquids.remove(liquid, maxUsed); + }else{ //is heater + float heat = coolantPower * liquid.heatCapacity / 4f; //heat created per unit of liquid + float maxUsed = Math.min(Math.min(entity.liquids.get(liquid), (1f - entity.heat) / heat), maxLiquidUse * Timers.delta()); //max liquid used + entity.heat += maxUsed * heat; + entity.liquids.remove(liquid, maxUsed); + } + } + + if(entity.heat > smokeThreshold){ + float smoke = 1.0f + (entity.heat - smokeThreshold) / (1f - smokeThreshold); //ranges from 1.0 to 2.0 + if(Mathf.chance(smoke / 20.0 * Timers.delta())){ + Effects.effect(BlockFx.reactorsmoke, tile.worldx() + Mathf.range(size * tilesize / 2f), + tile.worldy() + Mathf.random(size * tilesize / 2f)); + } + } + + entity.heat = Mathf.clamp(entity.heat); + + if(entity.heat >= 1f){ + entity.damage((int) entity.health); + }else{ + distributePower(tile); + } + } + + @Override + public void onDestroyed(Tile tile){ + super.onDestroyed(tile); + + NuclearReactorEntity entity = tile.entity(); + + int fuel = entity.items.get(consumes.item()); + + if(fuel < 5 && entity.heat < 0.5f) return; + + Effects.shake(6f, 16f, tile.worldx(), tile.worldy()); + Effects.effect(ExplosionFx.nuclearShockwave, tile.worldx(), tile.worldy()); + for(int i = 0; i < 6; i++){ + Timers.run(Mathf.random(40), () -> { + Effects.effect(BlockFx.nuclearcloud, tile.worldx(), tile.worldy()); + }); + } + + Damage.damage(tile.worldx(), tile.worldy(), explosionRadius * tilesize, explosionDamage * 4); + + + for(int i = 0; i < 20; i++){ + Timers.run(Mathf.random(50), () -> { + tr.rnd(Mathf.random(40f)); + Effects.effect(ExplosionFx.explosion, tr.x + tile.worldx(), tr.y + tile.worldy()); + }); + } + + for(int i = 0; i < 70; i++){ + Timers.run(Mathf.random(80), () -> { + tr.rnd(Mathf.random(120f)); + Effects.effect(BlockFx.nuclearsmoke, tr.x + tile.worldx(), tr.y + tile.worldy()); + }); + } + } + + @Override + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + return tile.entity.liquids.get(liquid) + amount < liquidCapacity && liquid.temperature <= 0.5f && + (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.01f); + } + + @Override + public void draw(Tile tile){ + super.draw(tile); + + NuclearReactorEntity entity = tile.entity(); + + Draw.color(coolColor, hotColor, entity.heat); + Draw.rect("white", tile.drawx(), tile.drawy(), size * tilesize, size * tilesize); + + Draw.color(entity.liquids.current().color); + Draw.alpha(entity.liquids.currentAmount() / liquidCapacity); + Draw.rect(topRegion, tile.drawx(), tile.drawy()); + + if(entity.heat > flashThreshold){ + float flash = 1f + ((entity.heat - flashThreshold) / (1f - flashThreshold)) * 5.4f; + entity.flash += flash * Timers.delta(); + Draw.color(Color.RED, Color.YELLOW, Mathf.absin(entity.flash, 9f, 1f)); + Draw.alpha(0.6f); + Draw.rect(lightsRegion, tile.drawx(), tile.drawy()); + } + + Draw.reset(); + } + + @Override + public TileEntity getEntity(){ + return new NuclearReactorEntity(); + } + + public static class NuclearReactorEntity extends GeneratorEntity{ + public float heat; + public float flash; + + @Override + public void write(DataOutputStream stream) throws IOException{ + super.write(stream); + stream.writeFloat(heat); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + super.read(stream); + heat = stream.readFloat(); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerDistributor.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerDistributor.java index bb2a5ac1f8..991bd165d2 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerDistributor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerDistributor.java @@ -7,9 +7,9 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.PowerBlock; import io.anuke.ucore.core.Timers; -public class PowerDistributor extends PowerBlock { +public class PowerDistributor extends PowerBlock{ - public PowerDistributor(String name) { + public PowerDistributor(String name){ super(name); } @@ -26,7 +26,7 @@ public class PowerDistributor extends PowerBlock { for(GridPoint2 point : Edges.getEdges(size)){ Tile target = tile.getNearby(point); if(target != null && target.block().hasPower && - shouldDistribute(tile, target)) sources ++; + shouldDistribute(tile, target)) sources++; } if(sources == 0) return; @@ -39,7 +39,7 @@ public class PowerDistributor extends PowerBlock { target = target.target(); if(target.block().hasPower && shouldDistribute(tile, target)){ - float diff = (tile.entity.power.amount / powerCapacity - target.entity.power.amount / target.block().powerCapacity)/1.4f; + float diff = (tile.entity.power.amount / powerCapacity - target.entity.power.amount / target.block().powerCapacity) / 1.4f; float transmit = Math.min(result * Timers.delta(), diff * powerCapacity); if(target.block().acceptPower(target, tile, transmit)){ @@ -50,7 +50,7 @@ public class PowerDistributor extends PowerBlock { } } - protected boolean shouldDistribute(Tile tile, Tile other) { + protected boolean shouldDistribute(Tile tile, Tile other){ other = other.target(); //only generators can distribute to other generators return (!(other.block() instanceof PowerGenerator) || tile.block() instanceof PowerGenerator) @@ -60,7 +60,7 @@ public class PowerDistributor extends PowerBlock { } @Override - public void update(Tile tile) { + public void update(Tile tile){ distributePower(tile); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java index 03a8cbf43a..5fac88bc26 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java @@ -4,16 +4,16 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.util.EnumSet; -public class PowerGenerator extends PowerDistributor { +public class PowerGenerator extends PowerDistributor{ - public PowerGenerator(String name) { + public PowerGenerator(String name){ super(name); baseExplosiveness = 5f; flags = EnumSet.of(BlockFlag.producer); } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new GeneratorEntity(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java index 331f2d4546..b2a7646e40 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java @@ -31,287 +31,291 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; public class PowerNode extends PowerBlock{ - public static final float thicknessScl = 0.7f; + public static final float thicknessScl = 0.7f; public static final float flashScl = 0.12f; - //last distribution block placed - private static int lastPlaced = -1; + //last distribution block placed + private static int lastPlaced = -1; - protected Translator t1 = new Translator(); - protected Translator t2 = new Translator(); + protected Translator t1 = new Translator(); + protected Translator t2 = new Translator(); - protected float laserRange = 6; - protected float powerSpeed = 0.5f; - protected int maxNodes = 3; + protected float laserRange = 6; + protected float powerSpeed = 0.5f; + protected int maxNodes = 3; - public PowerNode(String name){ - super(name); - expanded = true; - layer = Layer.power; - powerCapacity = 5f; - configurable = true; - } + public PowerNode(String name){ + super(name); + expanded = true; + layer = Layer.power; + powerCapacity = 5f; + configurable = true; + } - @Override - public void setBars(){} + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) + public static void linkPowerDistributors(Player player, Tile tile, Tile other){ - @Override - public void placed(Tile tile) { - Tile before = world.tile(lastPlaced); - if(linkValid(tile, before) && before.block() instanceof PowerNode){ - CallBlocks.linkPowerDistributors(null, tile, before); - } + DistributorEntity entity = tile.entity(); - lastPlaced = tile.packedPosition(); - } + if(!entity.links.contains(other.packedPosition())){ + entity.links.add(other.packedPosition()); + } - @Override - public void setStats(){ - super.setStats(); + if(other.block() instanceof PowerNode){ + DistributorEntity oe = other.entity(); - stats.add(BlockStat.powerRange, laserRange, StatUnit.blocks); - stats.add(BlockStat.powerTransferSpeed, powerSpeed * 60, StatUnit.powerSecond); - } + if(!oe.links.contains(tile.packedPosition())){ + oe.links.add(tile.packedPosition()); + } + } + } - @Override - public void update(Tile tile){ + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) + public static void unlinkPowerDistributors(Player player, Tile tile, Tile other){ + DistributorEntity entity = tile.entity(); + + entity.links.removeValue(other.packedPosition()); + + if(other.block() instanceof PowerNode){ + DistributorEntity oe = other.entity(); + + oe.links.removeValue(tile.packedPosition()); + } + } + + @Override + public void setBars(){ + } + + @Override + public void placed(Tile tile){ + Tile before = world.tile(lastPlaced); + if(linkValid(tile, before) && before.block() instanceof PowerNode){ + CallBlocks.linkPowerDistributors(null, tile, before); + } + + lastPlaced = tile.packedPosition(); + } + + @Override + public void setStats(){ + super.setStats(); + + stats.add(BlockStat.powerRange, laserRange, StatUnit.blocks); + stats.add(BlockStat.powerTransferSpeed, powerSpeed * 60 / 2f, StatUnit.powerSecond); //divided by 2 since passback exists + } + + @Override + public void update(Tile tile){ distributeLaserPower(tile); } @Override public boolean onConfigureTileTapped(Tile tile, Tile other){ - DistributorEntity entity = tile.entity(); - other = other.target(); + DistributorEntity entity = tile.entity(); + other = other.target(); - Tile result = other; + Tile result = other; - if(linkValid(tile, other)){ - if(linked(tile, other)){ - threads.run(() -> CallBlocks.unlinkPowerDistributors(null, tile, result)); - }else if(entity.links.size < maxNodes){ - threads.run(() -> CallBlocks.linkPowerDistributors(null, tile, result)); - } - return false; - } - return true; - } + if(linkValid(tile, other)){ + if(linked(tile, other)){ + threads.run(() -> CallBlocks.unlinkPowerDistributors(null, tile, result)); + }else if(entity.links.size < maxNodes){ + threads.run(() -> CallBlocks.linkPowerDistributors(null, tile, result)); + } + return false; + } + return true; + } - @Override - public void drawSelect(Tile tile){ - super.drawSelect(tile); + @Override + public void drawSelect(Tile tile){ + super.drawSelect(tile); Draw.color(Palette.power); Lines.stroke(1f); - Lines.poly(Edges.getPixelPolygon(laserRange), tile.worldx() - tilesize/2, tile.worldy() - tilesize/2, tilesize); + Lines.poly(Edges.getPixelPolygon(laserRange), tile.worldx() - tilesize / 2, tile.worldy() - tilesize / 2, tilesize); Draw.reset(); - } + } - @Override - public void drawConfigure(Tile tile){ - DistributorEntity entity = tile.entity(); + @Override + public void drawConfigure(Tile tile){ + DistributorEntity entity = tile.entity(); - Draw.color(Palette.accent); + Draw.color(Palette.accent); - Lines.stroke(1f); - Lines.square(tile.drawx(), tile.drawy(), - tile.block().size * tilesize / 2f + 1f + Mathf.absin(Timers.time(), 4f, 1f)); + Lines.stroke(1f); + Lines.square(tile.drawx(), tile.drawy(), + tile.block().size * tilesize / 2f + 1f + Mathf.absin(Timers.time(), 4f, 1f)); - Lines.stroke(1f); + Lines.stroke(1f); - Lines.poly(Edges.getPixelPolygon(laserRange), tile.worldx() - tilesize/2, tile.worldy() - tilesize/2, tilesize); + Lines.poly(Edges.getPixelPolygon(laserRange), tile.worldx() - tilesize / 2, tile.worldy() - tilesize / 2, tilesize); - Draw.color(Palette.power); + Draw.color(Palette.power); - for(int x = (int)(tile.x - laserRange); x <= tile.x + laserRange; x ++){ - for(int y = (int)(tile.y - laserRange); y <= tile.y + laserRange; y ++){ - Tile link = world.tile(x, y); - if(link != null) link = link.target(); + for(int x = (int) (tile.x - laserRange); x <= tile.x + laserRange; x++){ + for(int y = (int) (tile.y - laserRange); y <= tile.y + laserRange; y++){ + Tile link = world.tile(x, y); + if(link != null) link = link.target(); - if(link != tile && linkValid(tile, link, false)){ - boolean linked = linked(tile, link); - Draw.color(linked ? Palette.place : Palette.breakInvalid); + if(link != tile && linkValid(tile, link, false)){ + boolean linked = linked(tile, link); + Draw.color(linked ? Palette.place : Palette.breakInvalid); - Lines.square(link.drawx(), link.drawy(), - link.block().size * tilesize / 2f + 1f + (linked ? 0f : Mathf.absin(Timers.time(), 4f, 1f))); + Lines.square(link.drawx(), link.drawy(), + link.block().size * tilesize / 2f + 1f + (linked ? 0f : Mathf.absin(Timers.time(), 4f, 1f))); - if((entity.links.size >= maxNodes || (link.block() instanceof PowerNode && ((DistributorEntity)link.entity).links.size >= ((PowerNode)link.block()).maxNodes)) && !linked){ - Draw.color(); - Draw.rect("cross-" + link.block().size, link.drawx(), link.drawy()); - } - } - } - } + if((entity.links.size >= maxNodes || (link.block() instanceof PowerNode && ((DistributorEntity) link.entity).links.size >= ((PowerNode) link.block()).maxNodes)) && !linked){ + Draw.color(); + Draw.rect("cross-" + link.block().size, link.drawx(), link.drawy()); + } + } + } + } - Draw.reset(); - } + Draw.reset(); + } - @Override - public void drawPlace(int x, int y, int rotation, boolean valid){ + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ Draw.color(Palette.placing); Lines.stroke(1f); - Lines.poly(Edges.getPixelPolygon(laserRange), x * tilesize - tilesize/2, y * tilesize - tilesize/2, tilesize); + Lines.poly(Edges.getPixelPolygon(laserRange), x * tilesize - tilesize / 2, y * tilesize - tilesize / 2, tilesize); Draw.reset(); - } + } - @Override - public void drawLayer(Tile tile){ - if(!Settings.getBool("lasers")) return; + @Override + public void drawLayer(Tile tile){ + if(!Settings.getBool("lasers")) return; - DistributorEntity entity = tile.entity(); + DistributorEntity entity = tile.entity(); - entity.laserColor = Mathf.lerpDelta(entity.laserColor, Mathf.clamp(entity.powerRecieved/(powerSpeed)), 0.08f); + entity.laserColor = Mathf.lerpDelta(entity.laserColor, Mathf.clamp(entity.powerRecieved / (powerSpeed)), 0.08f); - Draw.color(Palette.powerLaserFrom, Palette.powerLaserTo, entity.laserColor * (1f-flashScl) + Mathf.sin(Timers.time(), 1.7f, flashScl)); + Draw.color(Palette.powerLaserFrom, Palette.powerLaserTo, entity.laserColor * (1f - flashScl) + Mathf.sin(Timers.time(), 1.7f, flashScl)); - for(int i = 0; i < entity.links.size; i ++){ - Tile link = world.tile(entity.links.get(i)); - if(linkValid(tile, link)) drawLaser(tile, link); + for(int i = 0; i < entity.links.size; i++){ + Tile link = world.tile(entity.links.get(i)); + if(linkValid(tile, link)) drawLaser(tile, link); } - Draw.color(); - } + Draw.color(); + } - @Override - public float addPower(Tile tile, float amount){ - DistributorEntity entity = tile.entity(); + @Override + public float addPower(Tile tile, float amount){ + DistributorEntity entity = tile.entity(); - if(entity.lastRecieved != threads.getFrameID()){ - entity.lastRecieved = threads.getFrameID(); - entity.powerRecieved = 0f; - } + if(entity.lastRecieved != threads.getFrameID()){ + entity.lastRecieved = threads.getFrameID(); + entity.powerRecieved = 0f; + } - float added = super.addPower(tile, amount); - entity.powerRecieved += added; - return added; - } + float canAccept = Math.min(powerCapacity * Timers.delta() - tile.entity.power.amount, amount); - protected boolean shouldDistribute(Tile tile, Tile other) { - return other.entity.power.amount / other.block().powerCapacity <= tile.entity.power.amount / powerCapacity && - !(other.block() instanceof PowerGenerator); //do not distribute to power generators - } + tile.entity.power.amount += canAccept; + entity.powerRecieved += canAccept; - protected boolean shouldLeechPower(Tile tile, Tile other){ - return !(other.block() instanceof PowerNode) - && other.block() instanceof PowerDistributor //only suck power from batteries and power generators - && other.entity.power.amount / other.block().powerCapacity > tile.entity.power.amount / powerCapacity; - } + return canAccept; + } - protected void distributeLaserPower(Tile tile){ - DistributorEntity entity = tile.entity(); + protected boolean shouldDistribute(Tile tile, Tile other){ + return other.entity.power.amount / other.block().powerCapacity <= tile.entity.power.amount / powerCapacity && + !(other.block() instanceof PowerGenerator); //do not distribute to power generators + } - if(Float.isNaN(entity.power.amount)){ - entity.power.amount = 0f; - } + protected boolean shouldLeechPower(Tile tile, Tile other){ + return !(other.block() instanceof PowerNode) + && other.block() instanceof PowerDistributor //only suck power from batteries and power generators + && other.entity.power.amount / other.block().powerCapacity > tile.entity.power.amount / powerCapacity; + } - int targets = 0; + protected void distributeLaserPower(Tile tile){ + DistributorEntity entity = tile.entity(); - //validate everything first. - for(int i = 0; i < entity.links.size; i ++){ - Tile target = world.tile(entity.links.get(i)); - if(!linkValid(tile, target)) { - entity.links.removeIndex(i); - i --; - }else if(shouldDistribute(tile, target)) { - targets++; - } - } + if(Float.isNaN(entity.power.amount)){ + entity.power.amount = 0f; + } - float result = Math.min(entity.power.amount / targets, powerSpeed * Timers.delta()); + int targets = 0; - for(int i = 0; i < entity.links.size; i ++){ - Tile target = world.tile(entity.links.get(i)); - if(shouldDistribute(tile, target)) { + //validate everything first. + for(int i = 0; i < entity.links.size; i++){ + Tile target = world.tile(entity.links.get(i)); + if(!linkValid(tile, target)){ + entity.links.removeIndex(i); + i--; + }else if(shouldDistribute(tile, target)){ + targets++; + } + } - float transmit = Math.min(result * Timers.delta(), entity.power.amount); - if (target.block().acceptPower(target, tile, transmit)) { - entity.power.amount -= target.block().addPower(target, transmit); - } - }else if(shouldLeechPower(tile, target)){ - float diff = (target.entity.power.amount / target.block().powerCapacity - tile.entity.power.amount / powerCapacity)/1.4f; - float transmit = Math.min(Math.min(target.block().powerCapacity * diff, target.entity.power.amount), powerCapacity - tile.entity.power.amount); - entity.power.amount += transmit; - target.entity.power.amount -= transmit; - } - } - } + float result = Math.min(entity.power.amount / targets, powerSpeed * Timers.delta()); - protected boolean linked(Tile tile, Tile other){ - return tile.entity().links.contains(other.packedPosition()); - } + for(int i = 0; i < entity.links.size; i++){ + Tile target = world.tile(entity.links.get(i)); + if(shouldDistribute(tile, target)){ - protected boolean linkValid(Tile tile, Tile link){ - return linkValid(tile, link, true); - } + float transmit = Math.min(result, entity.power.amount); + if(target.block().acceptPower(target, tile, transmit)){ + entity.power.amount -= target.block().addPower(target, transmit); + } + }else if(shouldLeechPower(tile, target)){ + float diff = (target.entity.power.amount / target.block().powerCapacity - tile.entity.power.amount / powerCapacity) / 1.4f; + float transmit = Math.min(Math.min(target.block().powerCapacity * diff, target.entity.power.amount), powerCapacity - tile.entity.power.amount); + entity.power.amount += transmit; + target.entity.power.amount -= transmit; + } + } + } - protected boolean linkValid(Tile tile, Tile link, boolean checkMaxNodes){ - if(!(tile != link && link != null && link.block().hasPower)) return false; + protected boolean linked(Tile tile, Tile other){ + return tile.entity().links.contains(other.packedPosition()); + } - if(link.block() instanceof PowerNode){ - DistributorEntity oe = link.entity(); + protected boolean linkValid(Tile tile, Tile link){ + return linkValid(tile, link, true); + } - return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) <= Math.max(laserRange * tilesize, - ((PowerNode)link.block()).laserRange * tilesize) - tilesize/2f - + (link.block().size-1)*tilesize/2f + (tile.block().size-1)*tilesize/2f && - (!checkMaxNodes || (oe.links.size < ((PowerNode)link.block()).maxNodes || oe.links.contains(tile.packedPosition()))); - }else{ - return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) - <= laserRange * tilesize - tilesize/2f + (link.block().size-1)*tilesize; - } - } + protected boolean linkValid(Tile tile, Tile link, boolean checkMaxNodes){ + if(!(tile != link && link != null && link.block().hasPower)) return false; - protected void drawLaser(Tile tile, Tile target){ + if(link.block() instanceof PowerNode){ + DistributorEntity oe = link.entity(); + + return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) <= Math.max(laserRange * tilesize, + ((PowerNode) link.block()).laserRange * tilesize) - tilesize / 2f + + (link.block().size - 1) * tilesize / 2f + (tile.block().size - 1) * tilesize / 2f && + (!checkMaxNodes || (oe.links.size < ((PowerNode) link.block()).maxNodes || oe.links.contains(tile.packedPosition()))); + }else{ + return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) + <= laserRange * tilesize - tilesize / 2f + (link.block().size - 1) * tilesize; + } + } + + protected void drawLaser(Tile tile, Tile target){ float x1 = tile.drawx(), y1 = tile.drawy(), x2 = target.drawx(), y2 = target.drawy(); float angle1 = Angles.angle(x1, y1, x2, y2); float angle2 = angle1 + 180f; - t1.trns(angle1, tile.block().size * tilesize/2f + 1f); - t2.trns(angle2, target.block().size * tilesize/2f + 1f); + t1.trns(angle1, tile.block().size * tilesize / 2f + 1f); + t2.trns(angle2, target.block().size * tilesize / 2f + 1f); Shapes.laser("laser", "laser-end", x1 + t1.x, y1 + t1.y, x2 + t2.x, y2 + t2.y, thicknessScl); - } - - @Override - public TileEntity getEntity() { - return new DistributorEntity(); } - @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) - public static void linkPowerDistributors(Player player, Tile tile, Tile other){ - - DistributorEntity entity = tile.entity(); - - if(!entity.links.contains(other.packedPosition())){ - entity.links.add(other.packedPosition()); - } - - if(other.block() instanceof PowerNode){ - DistributorEntity oe = other.entity(); - - if(!oe.links.contains(tile.packedPosition()) ){ - oe.links.add(tile.packedPosition()); - } - } - } - - @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) - public static void unlinkPowerDistributors(Player player, Tile tile, Tile other){ - DistributorEntity entity = tile.entity(); - - entity.links.removeValue(other.packedPosition()); - - if(other.block() instanceof PowerNode){ - DistributorEntity oe = other.entity(); - - oe.links.removeValue(tile.packedPosition()); - } - } + @Override + public TileEntity getEntity(){ + return new DistributorEntity(); + } public static class DistributorEntity extends TileEntity{ public float laserColor = 0f; @@ -319,21 +323,21 @@ public class PowerNode extends PowerBlock{ public long lastRecieved = 0; public IntArray links = new IntArray(); - @Override - public void write(DataOutputStream stream) throws IOException { - stream.writeShort(links.size); - for(int i = 0; i < links.size; i ++){ - stream.writeInt(links.get(i)); - } - } + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeShort(links.size); + for(int i = 0; i < links.size; i++){ + stream.writeInt(links.get(i)); + } + } - @Override - public void read(DataInputStream stream) throws IOException { - short amount = stream.readShort(); - for(int i = 0; i < amount; i ++){ - links.add(stream.readInt()); - } - } - } + @Override + public void read(DataInputStream stream) throws IOException{ + short amount = stream.readShort(); + for(int i = 0; i < amount; i++){ + links.add(stream.readInt()); + } + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java index 5dee77caf8..651ea6af5d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java @@ -5,8 +5,10 @@ import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Timers; -public class SolarGenerator extends PowerGenerator { - /**power generated per frame*/ +public class SolarGenerator extends PowerGenerator{ + /** + * power generated per frame + */ protected float generation = 0.005f; public SolarGenerator(String name){ @@ -14,7 +16,7 @@ public class SolarGenerator extends PowerGenerator { } @Override - public void setStats() { + public void setStats(){ super.setStats(); stats.add(BlockStat.maxPowerGeneration, generation * 60f, StatUnit.powerSecond); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/TurbineGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/TurbineGenerator.java index d29d5bb67e..7416986d6e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/TurbineGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/TurbineGenerator.java @@ -1,57 +1,21 @@ package io.anuke.mindustry.world.blocks.power; -import io.anuke.mindustry.content.Liquids; -import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.ucore.core.Timers; +import io.anuke.mindustry.world.consumers.ConsumeLiquid; -public class TurbineGenerator extends BurnerGenerator { - protected float auxLiquidUse = 0.1f; - protected Liquid auxLiquid = Liquids.water; - protected float auxLiquidCapacity = 10; +//TODO +public class TurbineGenerator extends BurnerGenerator{ - public TurbineGenerator(String name) { + public TurbineGenerator(String name){ super(name); + singleLiquid = false; + + consumes.require(ConsumeLiquid.class); } @Override - public void setStats() { - super.setStats(); - - stats.add(BlockStat.inputLiquidAux, auxLiquid); - } - - @Override - public void update(Tile tile) { - TurbineEntity entity = tile.entity(); - float used = Math.min(auxLiquidUse * Timers.delta(), auxLiquidCapacity); - - if(entity.aux >= used){ - super.update(tile); - entity.aux -= used; - } - } - - @Override - public float handleAuxLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - TurbineEntity entity = tile.entity(); - if(liquid == auxLiquid){ - float accepted = Math.min(auxLiquidCapacity - entity.aux, amount); - entity.aux += accepted; - return accepted; - }else { - return 0; - } - } - - @Override - public TileEntity getEntity() { - return new TurbineEntity(); - } - - public class TurbineEntity extends ItemGeneratorEntity{ - public float aux; + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ + return super.acceptLiquid(tile, source, liquid, amount) || liquid == consumes.liquid() && tile.entity.liquids.get(consumes.liquid()) < liquidCapacity; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Compressor.java b/core/src/io/anuke/mindustry/world/blocks/production/Compressor.java index a7b85759f5..189dfd1456 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Compressor.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Compressor.java @@ -4,60 +4,45 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.production.GenericCrafter.GenericCrafterEntity; -import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public class Compressor extends PowerCrafter { +public class Compressor extends PowerCrafter{ + protected TextureRegion liquidRegion, topRegion; + protected TextureRegion[] frameRegions; - public Compressor(String name) { + public Compressor(String name){ super(name); hasLiquids = true; } @Override - public void update(Tile tile) { - GenericCrafterEntity entity = tile.entity(); + public void load(){ + super.load(); - float powerUsed = Math.min(Timers.delta() * powerUse, tile.entity.power.amount); - float liquidAdded = Math.min(outputLiquidAmount * Timers.delta(), liquidCapacity - entity.liquids.amount); - int itemsUsed = Mathf.ceil(1 + input.amount * entity.progress); - - if(entity.power.amount > powerUsed && entity.items.hasItem(input.item, itemsUsed) && liquidAdded > 0.001f){ - entity.progress += 1f/craftTime; - entity.totalProgress += Timers.delta(); - handleLiquid(tile, tile, outputLiquid, liquidAdded); + frameRegions = new TextureRegion[3]; + for(int i = 0; i < 3; i++){ + frameRegions[i] = Draw.region(name + "-frame" + i); } - if(entity.progress >= 1f){ - entity.items.removeItem(input); - if(outputItem != null) offloadNear(tile, outputItem); - entity.progress = 0f; - } - - if(outputItem != null && entity.timer.get(timerDump, 5)){ - tryDump(tile, outputItem); - } - - if(outputLiquid != null){ - tryDumpLiquid(tile); - } + liquidRegion = Draw.region(name + "-liquid"); + topRegion = Draw.region(name + "-top"); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ GenericCrafterEntity entity = tile.entity(); - Draw.rect(name, tile.drawx(), tile.drawy()); - Draw.rect(name + "-frame" + (int) Mathf.absin(entity.totalProgress, 5f, 2.999f), tile.drawx(), tile.drawy()); - Draw.color(Color.CLEAR, tile.entity.liquids.liquid.color, tile.entity.liquids.amount / liquidCapacity); - Draw.rect(name + "-liquid", tile.drawx(), tile.drawy()); + Draw.rect(region, tile.drawx(), tile.drawy()); + Draw.rect(frameRegions[(int) Mathf.absin(entity.totalProgress, 5f, 2.999f)], tile.drawx(), tile.drawy()); + Draw.color(Color.CLEAR, tile.entity.liquids.current().color, tile.entity.liquids.total() / liquidCapacity); + Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); - Draw.rect(name + "-top", tile.drawx(), tile.drawy()); + Draw.rect(topRegion, tile.drawx(), tile.drawy()); } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ return new TextureRegion[]{Draw.region(name), Draw.region(name + "-top")}; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java b/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java index 52bf4488a4..507e1256ea 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java @@ -19,75 +19,83 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class Cultivator extends Drill { +public class Cultivator extends Drill{ protected Color plantColor = Color.valueOf("648b55"); protected Color plantColorLight = Color.valueOf("73a75f"); protected Color bottomColor = Color.valueOf("474747"); + protected TextureRegion middleRegion, topRegion; protected Item result; protected SeedRandom random = new SeedRandom(0); protected float recurrence = 6f; - public Cultivator(String name) { + public Cultivator(String name){ super(name); drillEffect = Fx.none; } @Override - public void setStats() { + public void setStats(){ super.setStats(); stats.remove(BlockStat.drillTier); stats.add(BlockStat.drillTier, table -> { - table.addImage("grass1").size(8*3).padBottom(3).padTop(3); + table.addImage("grass1").size(8 * 3).padBottom(3).padTop(3); }); } @Override - public void update(Tile tile) { - super.update(tile); + public void load(){ + super.load(); - CultivatorEntity entity = tile.entity(); - entity.warmup = Mathf.lerpDelta(entity.warmup, - tile.entity.liquids.amount > liquidUse ? 1f : 0f, 0.015f); + middleRegion = Draw.region(name + "-middle"); + topRegion = Draw.region(name + "-top"); } @Override - public void draw(Tile tile) { + public void update(Tile tile){ + super.update(tile); + + CultivatorEntity entity = tile.entity(); + entity.warmup = Mathf.lerpDelta(entity.warmup, entity.cons.valid() ? 1f : 0f, 0.015f); + } + + @Override + public void draw(Tile tile){ CultivatorEntity entity = tile.entity(); - Draw.rect(name, tile.drawx(), tile.drawy()); + Draw.rect(region, tile.drawx(), tile.drawy()); Draw.color(plantColor); Draw.alpha(entity.warmup); - Draw.rect(name + "-middle", tile.drawx(), tile.drawy()); + Draw.rect(middleRegion, tile.drawx(), tile.drawy()); Draw.color(bottomColor, plantColorLight, entity.warmup); random.setSeed(tile.packedPosition()); - for(int i = 0; i < 12; i ++){ + for(int i = 0; i < 12; i++){ float offset = random.nextFloat() * 999999f; float x = random.range(4f), y = random.range(4f); float life = 1f - (((Timers.time() + offset) / 50f) % recurrence); if(life > 0){ - Lines.stroke(entity.warmup * (life*1f + 0.2f)); - Lines.poly(tile.drawx() + x, tile.drawy() + y, 8, (1f-life) * 3f); + Lines.stroke(entity.warmup * (life * 1f + 0.2f)); + Lines.poly(tile.drawx() + x, tile.drawy() + y, 8, (1f - life) * 3f); } } Draw.color(); - Draw.rect(name + "-top", tile.drawx(), tile.drawy()); + Draw.rect(topRegion, tile.drawx(), tile.drawy()); } @Override - public TextureRegion[] getIcon() { - return new TextureRegion[]{Draw.region(name), Draw.region(name + "-top"), }; + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name), Draw.region(name + "-top"),}; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new CultivatorEntity(); } @@ -97,7 +105,7 @@ public class Cultivator extends Drill { } @Override - public Item getDrop(Tile tile) { + public Item getDrop(Tile tile){ return Items.biomatter; } @@ -105,12 +113,12 @@ public class Cultivator extends Drill { public float warmup; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeFloat(warmup); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ warmup = stream.readFloat(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java index 1856f63c32..5d7951a5a4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java @@ -8,9 +8,9 @@ import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.consumers.ConsumeLiquid; import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; @@ -25,239 +25,231 @@ import static io.anuke.mindustry.Vars.control; import static io.anuke.mindustry.Vars.headless; public class Drill extends Block{ - protected final static float hardnessDrillMultiplier = 50f; - protected final int timerDump = timers++; + protected final static float hardnessDrillMultiplier = 50f; + protected final int timerDump = timers++; - protected final Array drawTiles = new Array<>(); - protected final Array toAdd = new Array<>(); + protected final Array drawTiles = new Array<>(); + protected final Array toAdd = new Array<>(); - /**Maximum tier of blocks this drill can mine.*/ - protected int tier; - /**Base time to drill one ore, in frames.*/ - protected float drillTime = 300; - /**power use per frame.*/ - public float powerUse = 0.08f; - /**liquid use per frame.*/ - protected float liquidUse = 0.05f; - /**Input liquid. Set hasLiquids to true so this is used.*/ - protected Liquid inputLiquid = Liquids.water; - /**Whether the liquid is required to drill. If false, then it will be used as a speed booster.*/ - protected boolean liquidRequired = false; - /**How many times faster the drill will progress when boosted by liquid.*/ - protected float liquidBoostIntensity = 1.6f; - /**Speed at which the drill speeds up.*/ - protected float warmupSpeed = 0.02f; + /** + * Maximum tier of blocks this drill can mine. + */ + protected int tier; + /** + * Base time to drill one ore, in frames. + */ + protected float drillTime = 300; + /** + * Whether the liquid is required to drill. If false, then it will be used as a speed booster. + */ + protected boolean liquidRequired = false; + /** + * How many times faster the drill will progress when boosted by liquid. + */ + protected float liquidBoostIntensity = 1.6f; + /** + * Speed at which the drill speeds up. + */ + protected float warmupSpeed = 0.02f; - /**Effect played when an item is produced. This is colored.*/ - protected Effect drillEffect = BlockFx.mine; - /**Speed the drill bit rotates at.*/ - protected float rotateSpeed = 2f; - /**Effect randomly played while drilling.*/ - protected Effect updateEffect = BlockFx.pulverizeSmall; - /**Chance the update effect will appear.*/ - protected float updateEffectChance = 0.02f; + /** + * Effect played when an item is produced. This is colored. + */ + protected Effect drillEffect = BlockFx.mine; + /** + * Speed the drill bit rotates at. + */ + protected float rotateSpeed = 2f; + /** + * Effect randomly played while drilling. + */ + protected Effect updateEffect = BlockFx.pulverizeSmall; + /** + * Chance the update effect will appear. + */ + protected float updateEffectChance = 0.02f; - protected boolean drawRim = false; + protected boolean drawRim = false; - protected Color heatColor = Color.valueOf("ff5512"); - protected TextureRegion rimRegion; - protected TextureRegion rotatorRegion; - protected TextureRegion topRegion; + protected Color heatColor = Color.valueOf("ff5512"); + protected TextureRegion rimRegion; + protected TextureRegion rotatorRegion; + protected TextureRegion topRegion; - public Drill(String name) { - super(name); - update = true; - solid = true; - layer = Layer.overlay; - itemCapacity = 5; - group = BlockGroup.drills; - hasLiquids = true; - liquidCapacity = 5f; - hasItems = true; - } + public Drill(String name){ + super(name); + update = true; + solid = true; + layer = Layer.overlay; + itemCapacity = 5; + group = BlockGroup.drills; + hasLiquids = true; + liquidCapacity = 5f; + hasItems = true; - @Override - public void load() { - super.load(); - rimRegion = Draw.region(name + "-rim"); - rotatorRegion = Draw.region(name + "-rotator"); - topRegion = Draw.region(name + "-top"); - } + consumes.add(new ConsumeLiquid(Liquids.water, 0.05f)).optional(true); + } - @Override - public void draw(Tile tile) { - float s = 0.3f; - float ts = 0.6f; + @Override + public void load(){ + super.load(); + rimRegion = Draw.region(name + "-rim"); + rotatorRegion = Draw.region(name + "-rotator"); + topRegion = Draw.region(name + "-top"); + } - DrillEntity entity = tile.entity(); + @Override + public void draw(Tile tile){ + float s = 0.3f; + float ts = 0.6f; - Draw.rect(name, tile.drawx(), tile.drawy()); + DrillEntity entity = tile.entity(); - if(drawRim) { - Graphics.setAdditiveBlending(); - Draw.color(heatColor); - Draw.alpha(entity.warmup * ts * (1f-s + Mathf.absin(Timers.time(), 3f, s))); - Draw.rect(rimRegion, tile.drawx(), tile.drawy()); - Draw.color(); - Graphics.setNormalBlending(); - } + Draw.rect(region, tile.drawx(), tile.drawy()); - Draw.rect(rotatorRegion, tile.drawx(), tile.drawy(), entity.drillTime * rotateSpeed); + if(drawRim){ + Graphics.setAdditiveBlending(); + Draw.color(heatColor); + Draw.alpha(entity.warmup * ts * (1f - s + Mathf.absin(Timers.time(), 3f, s))); + Draw.rect(rimRegion, tile.drawx(), tile.drawy()); + Draw.color(); + Graphics.setNormalBlending(); + } - Draw.rect(topRegion, tile.drawx(), tile.drawy()); + Draw.rect(rotatorRegion, tile.drawx(), tile.drawy(), entity.drillTime * rotateSpeed); - if(!isMultiblock() && isValid(tile)) { - Draw.color(tile.floor().drops.item.color); - Draw.rect("blank", tile.worldx(), tile.worldy(), 2f, 2f); - Draw.color(); - } - } + Draw.rect(topRegion, tile.drawx(), tile.drawy()); - @Override - public TextureRegion[] getIcon() { - return new TextureRegion[]{Draw.region(name), Draw.region(name + "-rotator"), Draw.region(name + "-top")}; - } - - @Override - public void setStats(){ - super.setStats(); + if(!isMultiblock() && isValid(tile)){ + Draw.color(tile.floor().drops.item.color); + Draw.rect("blank", tile.worldx(), tile.worldy(), 2f, 2f); + Draw.color(); + } + } + + @Override + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name), Draw.region(name + "-rotator"), Draw.region(name + "-top")}; + } + + @Override + public void setStats(){ + super.setStats(); stats.add(BlockStat.drillTier, table -> { - Array list = new Array<>(); + Array list = new Array<>(); - for(Item item : Item.all()){ - if(tier >= item.hardness && Draw.hasRegion(item.name + "1")){ - list.add(item); - } - } + for(Item item : Item.all()){ + if(tier >= item.hardness && Draw.hasRegion(item.name + "1")){ + list.add(item); + } + } - for (int i = 0; i < list.size; i++) { - Item item = list.get(i); - table.addImage(item.name + "1").size(8*3).padRight(2).padLeft(2).padTop(3).padBottom(3); - if(i != list.size - 1){ - table.add("/"); - } - } - }); + for(int i = 0; i < list.size; i++){ + Item item = list.get(i); + table.addImage(item.name + "1").size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); + if(i != list.size - 1){ + table.add("/"); + } + } + }); - stats.add(BlockStat.drillSpeed, 60f/drillTime, StatUnit.itemsSecond); + stats.add(BlockStat.drillSpeed, 60f / drillTime, StatUnit.itemsSecond); + } - if(inputLiquid != null){ - stats.add(BlockStat.inputLiquid, inputLiquid); - } + @Override + public void update(Tile tile){ + toAdd.clear(); - if(hasPower){ - stats.add(BlockStat.powerUse, powerUse*60f, StatUnit.powerSecond); - } - } - - @Override - public void update(Tile tile){ - toAdd.clear(); + DrillEntity entity = tile.entity(); - DrillEntity entity = tile.entity(); + float multiplier = 0f; + float totalHardness = 0f; - float multiplier = 0f; - float totalHardness = 0f; + for(Tile other : tile.getLinkedTiles(tempTiles)){ + if(isValid(other)){ + Item drop = getDrop(other); + toAdd.add(drop); + totalHardness += drop.hardness; + multiplier += 1f; + } + } - for(Tile other : tile.getLinkedTiles(tempTiles)){ - if(isValid(other)){ - Item drop = getDrop(other); - toAdd.add(drop); - totalHardness += drop.hardness; - multiplier += 1f; - } - } + if(entity.timer.get(timerDump, 15)){ + tryDump(tile); + } - if(entity.timer.get(timerDump, 15)){ - tryDump(tile); - } + entity.drillTime += entity.warmup * Timers.delta(); - entity.drillTime += entity.warmup * Timers.delta(); + if(entity.items.total() < itemCapacity && toAdd.size > 0 && entity.cons.valid()){ - float powerUsed = Math.min(powerCapacity, powerUse * Timers.delta()); - float liquidUsed = Math.min(liquidCapacity, liquidUse * Timers.delta()); + float speed = 1f; - if(entity.items.totalItems() < itemCapacity && toAdd.size > 0 && - (!hasPower || entity.power.amount >= powerUsed) && - (!liquidRequired || entity.liquids.amount >= liquidUsed)){ + if(entity.consumed(ConsumeLiquid.class) && !liquidRequired){ + speed = liquidBoostIntensity; + } - if(hasPower) entity.power.amount -= powerUsed; - if(liquidRequired) entity.liquids.amount -= liquidUsed; + entity.warmup = Mathf.lerpDelta(entity.warmup, speed, warmupSpeed); + entity.progress += Timers.delta() * multiplier * speed * entity.warmup; - float speed = 1f; + if(Mathf.chance(Timers.delta() * updateEffectChance * entity.warmup)) + Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); + }else{ + entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, warmupSpeed); + return; + } - if(entity.liquids.amount >= liquidUsed && !liquidRequired){ - entity.liquids.amount -= liquidUsed; - speed = liquidBoostIntensity; - } + if(toAdd.size > 0 && entity.progress >= drillTime + hardnessDrillMultiplier * Math.max(totalHardness, 1f) / multiplier + && tile.entity.items.total() < itemCapacity){ - entity.warmup = Mathf.lerpDelta(entity.warmup, speed, warmupSpeed); - entity.progress += Timers.delta() * multiplier * speed * entity.warmup; + int index = entity.index % toAdd.size; + offloadNear(tile, toAdd.get(index)); - if(Mathf.chance(Timers.delta() * updateEffectChance * entity.warmup)) - Effects.effect(updateEffect, entity.x + Mathf.range(size*2f), entity.y + Mathf.range(size*2f)); - }else{ - entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, warmupSpeed); - return; - } + //unlock item content + if(!headless){ + control.database().unlockContent(toAdd.get(index)); + } - if(toAdd.size > 0 && entity.progress >= drillTime + hardnessDrillMultiplier*Math.max(totalHardness, 1f)/multiplier - && tile.entity.items.totalItems() < itemCapacity){ + entity.index++; + entity.progress = 0f; - int index = entity.index % toAdd.size; - offloadNear(tile, toAdd.get(index)); + Effects.effect(drillEffect, toAdd.get(index).color, + entity.x + Mathf.range(size), entity.y + Mathf.range(size)); + } + } - //unlock item content - if(!headless){ - control.database().unlockContent(toAdd.get(index)); - } + @Override + public boolean canPlaceOn(Tile tile){ + if(isMultiblock()){ + for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){ + if(isValid(other)){ + return true; + } + } + return false; + }else{ + return isValid(tile); + } + } - entity.index ++; - entity.progress = 0f; + @Override + public TileEntity getEntity(){ + return new DrillEntity(); + } - Effects.effect(drillEffect, toAdd.get(index).color, - entity.x + Mathf.range(size), entity.y + Mathf.range(size)); - } - } + public Item getDrop(Tile tile){ + return tile.floor().drops.item; + } - @Override - public boolean canPlaceOn(Tile tile) { - if(isMultiblock()){ - for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){ - if(isValid(other)){ - return true; - } - } - return false; - }else{ - return isValid(tile); - } - } + protected boolean isValid(Tile tile){ + return tile.floor().drops != null && tile.floor().drops.item.hardness <= tier; + } - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid; - } - - @Override - public TileEntity getEntity() { - return new DrillEntity(); - } - - public Item getDrop(Tile tile){ - return tile.floor().drops.item; - } - - protected boolean isValid(Tile tile){ - return tile.floor().drops != null && tile.floor().drops.item.hardness <= tier; - } - - public static class DrillEntity extends TileEntity{ - public float progress; - public int index; - public float warmup; - public float drillTime; - } + public static class DrillEntity extends TileEntity{ + public float progress; + public int index; + public float warmup; + public float drillTime; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java b/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java index 16465d6d45..3f3e9675ae 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java @@ -1,36 +1,31 @@ package io.anuke.mindustry.world.blocks.production; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import io.anuke.mindustry.content.Items; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.mindustry.world.consumers.ConsumeItem; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.Log; -public class Fracker extends SolidPump { - protected Liquid inputLiquid; - protected float inputLiquidUse; - protected float inputCapacity = 20f; - protected Item inputItem = Items.sand; +public class Fracker extends SolidPump{ protected float itemUseTime = 100f; protected TextureRegion liquidRegion; protected TextureRegion rotatorRegion; protected TextureRegion topRegion; - public Fracker(String name) { + public Fracker(String name){ super(name); hasItems = true; itemCapacity = 20; + singleLiquid = false; + + consumes.require(ConsumeItem.class); } @Override - public void load() { + public void load(){ super.load(); liquidRegion = Draw.region(name + "-liquid"); @@ -39,22 +34,18 @@ public class Fracker extends SolidPump { } @Override - public void setStats() { + public void setStats(){ super.setStats(); - - stats.add(BlockStat.inputItem, inputItem); - stats.add(BlockStat.inputLiquid, inputLiquid); - stats.add(BlockStat.liquidUse, 60f *inputLiquidUse, StatUnit.liquidSecond); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ FrackerEntity entity = tile.entity(); - Draw.rect(name, tile.drawx(), tile.drawy()); + Draw.rect(region, tile.drawx(), tile.drawy()); - Draw.color(tile.entity.liquids.liquid.color); - Draw.alpha(tile.entity.liquids.amount/liquidCapacity); + Draw.color(result.color); + Draw.alpha(tile.entity.liquids.get(result) / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); @@ -63,52 +54,39 @@ public class Fracker extends SolidPump { } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ return new TextureRegion[]{Draw.region(name), Draw.region(name + "-rotator"), Draw.region(name + "-top")}; } @Override - public void update(Tile tile) { + public void update(Tile tile){ FrackerEntity entity = tile.entity(); + Item item = consumes.item(); - while(entity.accumulator > itemUseTime && entity.items.hasItem(inputItem, 1)){ - entity.items.removeItem(inputItem, 1); + while(entity.accumulator > itemUseTime && entity.items.has(item, 1)){ + entity.items.remove(item, 1); entity.accumulator -= itemUseTime; } - if(entity.input >= Math.min(inputLiquidUse * Timers.delta(), inputCapacity) && entity.accumulator < itemUseTime){ + if(entity.cons.valid() && entity.accumulator < itemUseTime){ super.update(tile); - entity.input -= inputLiquidUse * Timers.delta(); entity.accumulator += Timers.delta(); }else{ - tryDumpLiquid(tile); + tryDumpLiquid(tile, result); } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return item == inputItem && tile.entity.items.totalItems() < itemCapacity; - } - - @Override - public float handleAuxLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - if(liquid != inputLiquid){ - return 0f; - }else{ - FrackerEntity entity = tile.entity(); - float accepted = Math.min(inputCapacity - entity.input, amount); - entity.input += accepted; - return accepted; - } - } - - @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new FrackerEntity(); } + @Override + public float typeLiquid(Tile tile){ + return tile.entity.liquids.get(result); + } + public static class FrackerEntity extends SolidPumpEntity{ - public float input; public float accumulator; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java index 1173847e9b..9c0f60ba75 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java @@ -5,11 +5,10 @@ import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.content.fx.Fx; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.ItemStack; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.consumers.ConsumeItem; import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; @@ -23,134 +22,112 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import static io.anuke.mindustry.Vars.control; +import static io.anuke.mindustry.Vars.headless; + public class GenericCrafter extends Block{ - protected final int timerDump = timers++; - - /**Can be null. If you use this, make sure to set hasItems to true!*/ - protected ItemStack inputItem; - /**Can be null. If you use this, make sure to set hasLiquids to true!*/ - protected Liquid inputLiquid; - /**Required.*/ - protected Item output; - protected float craftTime = 80; - protected float powerUse; - protected float liquidUse; - protected Effect craftEffect = BlockFx.purify; - protected Effect updateEffect = Fx.none; - protected float updateEffectChance = 0.04f; + protected final int timerDump = timers++; - public GenericCrafter(String name) { - super(name); - update = true; - solid = true; - health = 60; - } + protected Item output; + protected float craftTime = 80; + protected Effect craftEffect = BlockFx.purify; + protected Effect updateEffect = Fx.none; + protected float updateEffectChance = 0.04f; - @Override - public void setBars(){ - super.setBars(); + public GenericCrafter(String name){ + super(name); + update = true; + solid = true; + health = 60; + } - if(inputItem != null) bars.replace(new BlockBar(BarType.inventory, true, - tile -> (float)tile.entity.items.getItem(inputItem.item) / itemCapacity)); - } - - @Override - public void setStats(){ - super.setStats(); - stats.add(BlockStat.craftSpeed, 60f/craftTime, StatUnit.itemsSecond); - stats.add(BlockStat.outputItem, output); + @Override + public void setBars(){ + super.setBars(); - if(inputLiquid != null) stats.add(BlockStat.inputLiquid, inputLiquid); - if(inputLiquid != null) stats.add(BlockStat.liquidUse, (liquidUse * craftTime), StatUnit.liquidSecond); - if(inputItem != null) stats.add(BlockStat.inputItem, inputItem); - if(hasPower) stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); - } - - @Override - public void draw(Tile tile){ - Draw.rect(name(), tile.drawx(), tile.drawy()); - - if(!hasLiquids) return; - - Draw.color(tile.entity.liquids.liquid.color); - Draw.alpha(tile.entity.liquids.amount / liquidCapacity); - Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2); - Draw.color(); - } + if(consumes.has(ConsumeItem.class)) bars.replace(new BlockBar(BarType.inventory, true, + tile -> (float) tile.entity.items.get(consumes.item()) / itemCapacity)); + } - @Override - public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name)}; - } - - @Override - public void update(Tile tile){ - GenericCrafterEntity entity = tile.entity(); + @Override + public void setStats(){ + super.setStats(); + stats.add(BlockStat.craftSpeed, 60f / craftTime, StatUnit.itemsSecond); + stats.add(BlockStat.outputItem, output); + } - float powerUsed = Math.min(powerCapacity, powerUse * Timers.delta()); - float liquidUsed = Math.min(liquidCapacity, liquidUse * Timers.delta()); - int itemsUsed = (inputItem == null ? 0 : (int)(1 + inputItem.amount * entity.progress)); + @Override + public void draw(Tile tile){ + Draw.rect(name(), tile.drawx(), tile.drawy()); - if((!hasLiquids || entity.liquids.amount >= liquidUsed) && - (!hasPower || entity.power.amount >= powerUsed) && - (inputItem == null || entity.items.hasItem(inputItem.item, itemsUsed))){ + if(!hasLiquids) return; - entity.progress += 1f / craftTime * Timers.delta(); - entity.totalProgress += Timers.delta(); - entity.warmup = Mathf.lerp(entity.warmup, 1f, 0.02f); - if(hasPower) entity.power.amount -= powerUsed; - if(hasLiquids) entity.liquids.amount -= liquidUsed; + Draw.color(tile.entity.liquids.current().color); + Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2); + Draw.color(); + } - if(Mathf.chance(Timers.delta() * updateEffectChance)) - Effects.effect(updateEffect, entity.x + Mathf.range(size*4f), entity.y + Mathf.range(size*4)); - }else{ - entity.warmup = Mathf.lerp(entity.warmup, 0f, 0.02f); - } + @Override + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name)}; + } - if(entity.progress >= 1f){ - - if(inputItem != null) tile.entity.items.removeItem(inputItem); - offloadNear(tile, output); - Effects.effect(craftEffect, tile.drawx(), tile.drawy()); - entity.progress = 0f; - } - - if(tile.entity.timer.get(timerDump, 5)){ - tryDump(tile, output); - } - } - - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid; - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - TileEntity entity = tile.entity(); - return inputItem != null && item == inputItem.item && entity.items.getItem(inputItem.item) < itemCapacity; - } + @Override + public void update(Tile tile){ + GenericCrafterEntity entity = tile.entity(); - @Override - public TileEntity getEntity() { - return new GenericCrafterEntity(); - } + if(entity.cons.valid()){ - public static class GenericCrafterEntity extends TileEntity{ - public float progress; - public float totalProgress; - public float warmup; + entity.progress += 1f / craftTime * Timers.delta(); + entity.totalProgress += Timers.delta(); + entity.warmup = Mathf.lerp(entity.warmup, 1f, 0.02f); - @Override - public void write(DataOutputStream stream) throws IOException { - stream.writeFloat(progress); - stream.writeFloat(warmup); - } + if(Mathf.chance(Timers.delta() * updateEffectChance)) + Effects.effect(updateEffect, entity.x + Mathf.range(size * 4f), entity.y + Mathf.range(size * 4)); + }else{ + entity.warmup = Mathf.lerp(entity.warmup, 0f, 0.02f); + } - @Override - public void read(DataInputStream stream) throws IOException { - progress = stream.readFloat(); - warmup = stream.readFloat(); - } - } + if(entity.progress >= 1f){ + + if(consumes.has(ConsumeItem.class)) tile.entity.items.remove(consumes.item(), consumes.itemAmount()); + + //unlock output item + if(!headless){ + control.database().unlockContent(output); + } + + offloadNear(tile, output); + Effects.effect(craftEffect, tile.drawx(), tile.drawy()); + entity.progress = 0f; + } + + if(tile.entity.timer.get(timerDump, 5)){ + tryDump(tile, output); + } + } + + @Override + public TileEntity getEntity(){ + return new GenericCrafterEntity(); + } + + public static class GenericCrafterEntity extends TileEntity{ + public float progress; + public float totalProgress; + public float warmup; + + @Override + public void write(DataOutputStream stream) throws IOException{ + stream.writeFloat(progress); + stream.writeFloat(warmup); + } + + @Override + public void read(DataInputStream stream) throws IOException{ + progress = stream.readFloat(); + warmup = stream.readFloat(); + } + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java b/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java index 285288b9c5..ed8697ad2a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java @@ -8,8 +8,6 @@ import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; @@ -17,40 +15,31 @@ import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.util.Mathf; -public class Incinerator extends Block { - protected float powerUse = 0.07f; +public class Incinerator extends Block{ protected Effect effect = BlockFx.fuelburn; protected Color flameColor = Color.valueOf("ffad9d"); - public Incinerator(String name) { + public Incinerator(String name){ super(name); hasPower = true; hasLiquids = true; update = true; solid = true; + + consumes.power(0.05f); } @Override - public void setBars() { + public void setBars(){ super.setBars(); bars.remove(BarType.liquid); } @Override - public void setStats() { - super.setStats(); - - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); - } - - @Override - public void update(Tile tile) { + public void update(Tile tile){ IncineratorEntity entity = tile.entity(); - float used = Math.min(powerCapacity, powerUse * Timers.delta()); - - if(entity.power.amount >= used){ - entity.power.amount -= used; + if(entity.cons.valid()){ entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.04f); }else{ entity.heat = Mathf.lerpDelta(entity.heat, 0f, 0.02f); @@ -58,7 +47,7 @@ public class Incinerator extends Block { } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ super.draw(tile); IncineratorEntity entity = tile.entity(); @@ -67,7 +56,7 @@ public class Incinerator extends Block { float g = 0.3f; float r = 0.06f; - Draw.alpha(((1f-g) + Mathf.absin(Timers.time(), 8f, g) + Mathf.random(r) - r) * entity.heat); + Draw.alpha(((1f - g) + Mathf.absin(Timers.time(), 8f, g) + Mathf.random(r) - r) * entity.heat); Draw.tint(flameColor); Fill.circle(tile.drawx(), tile.drawy(), 2f); @@ -79,33 +68,33 @@ public class Incinerator extends Block { } @Override - public void handleItem(Item item, Tile tile, Tile source) { + public void handleItem(Item item, Tile tile, Tile source){ if(Mathf.chance(0.3)){ Effects.effect(effect, tile.drawx(), tile.drawy()); } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ IncineratorEntity entity = tile.entity(); return entity.heat > 0.5f; } @Override - public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount) { + public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ if(Mathf.chance(0.02)){ Effects.effect(effect, tile.drawx(), tile.drawy()); } } @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { + public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ IncineratorEntity entity = tile.entity(); return entity.heat > 0.5f; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new IncineratorEntity(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/LiquidMixer.java b/core/src/io/anuke/mindustry/world/blocks/production/LiquidMixer.java index 3f8523af20..11733cf392 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/LiquidMixer.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/LiquidMixer.java @@ -1,81 +1,92 @@ package io.anuke.mindustry.world.blocks.production; -import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.LiquidBlock; +import io.anuke.mindustry.world.consumers.ConsumeLiquid; +import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.mindustry.world.modules.LiquidModule; import io.anuke.ucore.core.Timers; +import io.anuke.ucore.graphics.Draw; public class LiquidMixer extends LiquidBlock{ - protected Liquid inputLiquid = Liquids.none; - protected Liquid outputLiquid = Liquids.none; - protected Item inputItem = null; + protected Liquid outputLiquid; protected float liquidPerItem = 50f; - protected float powerUse = 0f; - public LiquidMixer(String name) { + public LiquidMixer(String name){ super(name); hasItems = true; - hasPower = true; rotate = false; - liquidRegion = name() + "-liquid"; solid = true; + outputsLiquid = true; } @Override - public void setStats() { + public void setStats(){ super.setStats(); stats.add(BlockStat.liquidOutput, outputLiquid); - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); - stats.add(BlockStat.inputItem, inputItem); + } + + @Override + public void setBars(){ + super.setBars(); + + bars.remove(BarType.liquid); + bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.get(consumes.liquid()) / liquidCapacity)); + bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.get(outputLiquid) / liquidCapacity)); + } + + @Override + public boolean shouldConsume(Tile tile){ + return tile.entity.liquids.get(outputLiquid) < liquidCapacity; } @Override public void update(Tile tile){ - float used = Math.min(Timers.delta() * powerUse, tile.entity.power.amount); - - tryDumpLiquid(tile); - - if(tile.entity.power.amount > used) tile.entity.power.amount -= used; - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return item == inputItem && tile.entity.items.getItem(item) < itemCapacity; - } - - @Override - public float handleAuxLiquid(Tile tile, Tile source, Liquid liquid, float amount) { LiquidMixerEntity entity = tile.entity(); - if(liquid == inputLiquid && tile.entity.items.hasItem(inputItem, (int)((entity.accumulator + amount)/amount)) && - tile.entity.power.amount >= powerUse){ - - amount = Math.min(liquidCapacity - tile.entity.liquids.amount, amount); - - entity.accumulator += amount; - int items = (int)(entity.accumulator / liquidPerItem); - entity.items.removeItem(inputItem, items); - entity.accumulator %= liquidPerItem; - entity.liquids.liquid = outputLiquid; - entity.liquids.amount += amount; - return amount; - }else{ - return 0; + if(tile.entity.cons.valid()){ + float use = Math.min(consumes.get(ConsumeLiquid.class).used() * Timers.delta(), liquidCapacity - entity.liquids.get(outputLiquid)); + entity.accumulator += use; + entity.liquids.add(outputLiquid, use); + for(int i = 0; i < (int) (entity.accumulator / liquidPerItem); i++){ + if(!entity.items.has(consumes.item())) break; + entity.items.remove(consumes.item(), 1); + entity.accumulator -= liquidPerItem; + } } + + tryDumpLiquid(tile, outputLiquid); } @Override - public TileEntity getEntity() { + public void draw(Tile tile){ + LiquidModule mod = tile.entity.liquids; + + int rotation = rotate ? tile.getRotation() * 90 : 0; + + Draw.rect(bottomRegion, tile.drawx(), tile.drawy(), rotation); + + if(mod.total() > 0.001f){ + Draw.color(outputLiquid.color); + Draw.alpha(mod.get(outputLiquid) / liquidCapacity); + Draw.rect(liquidRegion, tile.drawx(), tile.drawy(), rotation); + Draw.color(); + } + + Draw.rect(topRegion, tile.drawx(), tile.drawy(), rotation); + } + + @Override + public TileEntity getEntity(){ return new LiquidMixerEntity(); } - static class LiquidMixerEntity extends TileEntity { + static class LiquidMixerEntity extends TileEntity{ float accumulator; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/PhaseWeaver.java b/core/src/io/anuke/mindustry/world/blocks/production/PhaseWeaver.java index baa50bb952..5a7369d1aa 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/PhaseWeaver.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/PhaseWeaver.java @@ -14,12 +14,12 @@ public class PhaseWeaver extends PowerSmelter{ protected TextureRegion bottomRegion; protected TextureRegion weaveRegion; - public PhaseWeaver(String name) { + public PhaseWeaver(String name){ super(name); } @Override - public void load() { + public void load(){ super.load(); bottomRegion = Draw.region(name + "-bottom"); @@ -27,7 +27,7 @@ public class PhaseWeaver extends PowerSmelter{ } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ if(icon == null){ icon = new TextureRegion[]{Draw.region(name + "-bottom"), Draw.region(name)}; } @@ -35,7 +35,7 @@ public class PhaseWeaver extends PowerSmelter{ } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ PowerSmelterEntity entity = tile.entity(); Draw.rect(bottomRegion, tile.drawx(), tile.drawy()); @@ -59,11 +59,11 @@ public class PhaseWeaver extends PowerSmelter{ tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size), tile.drawy(), 90, - size * Vars.tilesize /2f); + size * Vars.tilesize / 2f); Draw.reset(); } - Draw.rect(name, tile.drawx(), tile.drawy()); + Draw.rect(region, tile.drawx(), tile.drawy()); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/PlastaniumCompressor.java b/core/src/io/anuke/mindustry/world/blocks/production/PlastaniumCompressor.java index faf664d788..0a8c5fda3f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/PlastaniumCompressor.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/PlastaniumCompressor.java @@ -4,14 +4,14 @@ import io.anuke.mindustry.world.Tile; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -public class PlastaniumCompressor extends GenericCrafter { +public class PlastaniumCompressor extends GenericCrafter{ - public PlastaniumCompressor(String name) { + public PlastaniumCompressor(String name){ super(name); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ super.draw(tile); GenericCrafterEntity entity = tile.entity(); diff --git a/core/src/io/anuke/mindustry/world/blocks/production/PowerCrafter.java b/core/src/io/anuke/mindustry/world/blocks/production/PowerCrafter.java index bec6388a72..c43860227f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/PowerCrafter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/PowerCrafter.java @@ -2,30 +2,28 @@ package io.anuke.mindustry.world.blocks.production; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.production.GenericCrafter.GenericCrafterEntity; import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Timers; -import io.anuke.ucore.util.Mathf; public class PowerCrafter extends Block{ protected final int timerDump = timers++; - /**Required.*/ - protected ItemStack input; - /**Optional.*/ + /** + * Optional. + */ protected Item outputItem; - /**Optional. Set hasLiquids to true when using.*/ + /** + * Optional. Set hasLiquids to true when using. + */ protected Liquid outputLiquid; protected float outputLiquidAmount; - protected float powerUse; protected float craftTime; - public PowerCrafter(String name) { + public PowerCrafter(String name){ super(name); solid = true; update = true; @@ -34,10 +32,17 @@ public class PowerCrafter extends Block{ } @Override - public void setStats() { - super.setStats(); + public void init(){ + super.init(); - stats.add(BlockStat.inputItem, input); + if(outputLiquid != null){ + outputsLiquid = true; + } + } + + @Override + public void setStats(){ + super.setStats(); if(outputItem != null){ stats.add(BlockStat.outputItem, outputItem); @@ -46,26 +51,19 @@ public class PowerCrafter extends Block{ if(outputLiquid != null){ stats.add(BlockStat.liquidOutput, outputLiquid); } - - if(hasPower){ - stats.add(BlockStat.powerUse, 60f * powerUse, StatUnit.powerSecond); - } } @Override - public void update(Tile tile) { + public void update(Tile tile){ GenericCrafterEntity entity = tile.entity(); - float powerUsed = Math.min(Timers.delta() * powerUse, tile.entity.power.amount); - int itemsUsed = Mathf.ceil(1 + input.amount * entity.progress); - - if(entity.power.amount > powerUsed && entity.items.hasItem(input.item, itemsUsed)){ - entity.progress += 1f/craftTime; + if(entity.cons.valid()){ + entity.progress += 1f / craftTime; entity.totalProgress += Timers.delta(); } if(entity.progress >= 1f){ - entity.items.removeItem(input); + entity.items.remove(consumes.item(), consumes.itemAmount()); if(outputItem != null) offloadNear(tile, outputItem); if(outputLiquid != null) handleLiquid(tile, tile, outputLiquid, outputLiquidAmount); entity.progress = 0f; @@ -76,17 +74,12 @@ public class PowerCrafter extends Block{ } if(outputLiquid != null){ - tryDumpLiquid(tile); + tryDumpLiquid(tile, entity.liquids.current()); } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return item == input.item && tile.entity.items.getItem(input.item) < itemCapacity; - } - - @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new GenericCrafterEntity(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/PowerSmelter.java b/core/src/io/anuke/mindustry/world/blocks/production/PowerSmelter.java index fc552c8135..ebb561aa12 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/PowerSmelter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/PowerSmelter.java @@ -12,7 +12,6 @@ import io.anuke.mindustry.world.blocks.PowerBlock; import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; -import io.anuke.mindustry.world.meta.values.ItemListValue; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; @@ -24,16 +23,11 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class PowerSmelter extends PowerBlock { +public class PowerSmelter extends PowerBlock{ protected final int timerDump = timers++; protected final int timerCraft = timers++; - /**Recipe format: - * First item in each array: result - * Everything else in each array: requirements. Can have duplicates.*/ - protected ItemStack[] inputs; protected Item result; - protected float powerUse; protected float minFlux = 0.2f; protected int fluxNeeded = 1; @@ -51,7 +45,7 @@ public class PowerSmelter extends PowerBlock { protected TextureRegion topRegion; - public PowerSmelter(String name) { + public PowerSmelter(String name){ super(name); hasItems = true; update = true; @@ -60,7 +54,7 @@ public class PowerSmelter extends PowerBlock { } @Override - public void load() { + public void load(){ super.load(); topRegion = Draw.region(name + "-top"); } @@ -70,20 +64,17 @@ public class PowerSmelter extends PowerBlock { super.setBars(); bars.remove(BarType.inventory); - for(ItemStack item : inputs){ - bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.getItem(item.item) / itemCapacity)); + for(ItemStack item : consumes.items()){ + bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.get(item.item) / itemCapacity)); } } @Override public void setStats(){ super.setStats(); - //TODO input/outputs - stats.add(BlockStat.inputItems, new ItemListValue(inputs)); - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); stats.add(BlockStat.outputItem, result); - stats.add(BlockStat.craftSpeed, 60f/craftTime, StatUnit.itemsSecond); + stats.add(BlockStat.craftSpeed, 60f / craftTime, StatUnit.itemsSecond); stats.add(BlockStat.inputItemCapacity, itemCapacity, StatUnit.items); stats.add(BlockStat.outputItemCapacity, itemCapacity, StatUnit.items); } @@ -93,33 +84,27 @@ public class PowerSmelter extends PowerBlock { PowerSmelterEntity entity = tile.entity(); - if(entity.timer.get(timerDump, 5) && entity.items.hasItem(result)){ + if(entity.timer.get(timerDump, 5) && entity.items.has(result)){ tryDump(tile, result); } - float used = powerUse * Timers.delta(); - //heat it up if there's enough power - if(entity.power.amount > used){ - entity.power.amount -= used; - entity.heat += 1f / heatUpTime; + if(entity.cons.valid()){ + entity.heat += 1f / heatUpTime * Timers.delta(); if(Mathf.chance(Timers.delta() * burnEffectChance)) - Effects.effect(burnEffect, entity.x + Mathf.range(size*4f), entity.y + Mathf.range(size*4)); + Effects.effect(burnEffect, entity.x + Mathf.range(size * 4f), entity.y + Mathf.range(size * 4)); }else{ - entity.heat -= 1f / heatUpTime; + entity.heat -= 1f / heatUpTime * Timers.delta(); } entity.heat = Mathf.clamp(entity.heat); entity.time += entity.heat * Timers.delta(); - //make sure it has all the items - for(ItemStack item : inputs){ - if(!entity.items.hasItem(item.item, item.amount)){ - return; - } + if(!entity.cons.valid()){ + return; } - if(entity.items.getItem(result) >= itemCapacity //output full + if(entity.items.get(result) >= itemCapacity //output full || entity.heat <= minHeat //not burning || !entity.timer.get(timerCraft, craftTime)){ //not yet time return; @@ -130,8 +115,8 @@ public class PowerSmelter extends PowerBlock { if(useFlux){ //remove flux materials if present for(Item item : Item.all()){ - if(item.fluxiness >= minFlux && tile.entity.items.getItem(item) >= fluxNeeded){ - tile.entity.items.removeItem(item, fluxNeeded); + if(item.fluxiness >= minFlux && tile.entity.items.get(item) >= fluxNeeded){ + tile.entity.items.remove(item, fluxNeeded); //chance of not consuming inputs if flux material present consumeInputs = !Mathf.chance(item.fluxiness * baseFluxChance); @@ -140,9 +125,9 @@ public class PowerSmelter extends PowerBlock { } } - if(consumeInputs) { - for (ItemStack item : inputs) { - entity.items.removeItem(item.item, item.amount); + if(consumeInputs){ + for(ItemStack item : consumes.items()){ + entity.items.remove(item.item, item.amount); } } @@ -153,22 +138,22 @@ public class PowerSmelter extends PowerBlock { @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - for(ItemStack stack : inputs){ + for(ItemStack stack : consumes.items()){ if(stack.item == item){ - return tile.entity.items.getItem(item) < itemCapacity; + return tile.entity.items.get(item) < itemCapacity; } } if(useFlux && item.fluxiness >= minFlux){ - return tile.entity.items.getItem(item) < itemCapacity; + return tile.entity.items.get(item) < itemCapacity; } return false; } @Override - public int getMaximumAccepted(Tile tile, Item item) { - return itemCapacity - tile.entity.items.getItem(item); + public int getMaximumAccepted(Tile tile, Item item){ + return itemCapacity - tile.entity.items.get(item); } @Override @@ -183,7 +168,7 @@ public class PowerSmelter extends PowerBlock { float r = 0.06f; float cr = Mathf.random(0.1f); - Draw.alpha(((1f-g) + Mathf.absin(Timers.time(), 8f, g) + Mathf.random(r) - r) * entity.heat); + Draw.alpha(((1f - g) + Mathf.absin(Timers.time(), 8f, g) + Mathf.random(r) - r) * entity.heat); Draw.tint(flameColor); Fill.circle(tile.drawx(), tile.drawy(), 3f + Mathf.absin(Timers.time(), 5f, 2f) + cr); @@ -196,7 +181,7 @@ public class PowerSmelter extends PowerBlock { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new PowerSmelterEntity(); } @@ -205,12 +190,12 @@ public class PowerSmelter extends PowerBlock { public float time; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeFloat(heat); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ heat = stream.readFloat(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Pulverizer.java b/core/src/io/anuke/mindustry/world/blocks/production/Pulverizer.java index d9bdfe2930..72f80e138b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Pulverizer.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Pulverizer.java @@ -4,23 +4,31 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.graphics.Draw; -public class Pulverizer extends GenericCrafter { +public class Pulverizer extends GenericCrafter{ + protected TextureRegion rotatorRegion; - public Pulverizer(String name) { + public Pulverizer(String name){ super(name); hasItems = true; } @Override - public void draw(Tile tile) { - GenericCrafterEntity entity = tile.entity(); + public void load(){ + super.load(); - Draw.rect(name, tile.drawx(), tile.drawy()); - Draw.rect(name + "-rotator", tile.drawx(), tile.drawy(), entity.totalProgress * 2f); + rotatorRegion = Draw.region(name + "-rotator"); } @Override - public TextureRegion[] getIcon() { + public void draw(Tile tile){ + GenericCrafterEntity entity = tile.entity(); + + Draw.rect(region, tile.drawx(), tile.drawy()); + Draw.rect(rotatorRegion, tile.drawx(), tile.drawy(), entity.totalProgress * 2f); + } + + @Override + public TextureRegion[] getIcon(){ return new TextureRegion[]{Draw.region(name), Draw.region(name + "-rotator")}; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Pump.java b/core/src/io/anuke/mindustry/world/blocks/production/Pump.java index 7e98c47e3d..448f840801 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Pump.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Pump.java @@ -11,112 +11,103 @@ import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.Mathf; public class Pump extends LiquidBlock{ - protected final Array drawTiles = new Array<>(); - protected final Array updateTiles = new Array<>(); + protected final Array drawTiles = new Array<>(); + protected final Array updateTiles = new Array<>(); - /**Pump amount per tile this block is on.*/ - protected float pumpAmount = 1f; - /**Power used per frame per tile this block is on.*/ - protected float powerUse = 0f; - /**Maximum liquid tier this pump can use.*/ - protected int tier = 0; + /** + * Pump amount per tile this block is on. + */ + protected float pumpAmount = 1f; + /** + * Maximum liquid tier this pump can use. + */ + protected int tier = 0; - public Pump(String name) { - super(name); - layer = Layer.overlay; - liquidFlowFactor = 3f; - group = BlockGroup.liquids; - liquidRegion = "pump-liquid"; - floating = true; - } + public Pump(String name){ + super(name); + layer = Layer.overlay; + liquidFlowFactor = 3f; + group = BlockGroup.liquids; + floating = true; + } - @Override - public void setStats(){ - super.setStats(); - stats.add(BlockStat.liquidOutput, 60f*pumpAmount, StatUnit.liquidSecond); - } - - @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return false; - } - - @Override - public void draw(Tile tile){ - Draw.rect(name(), tile.drawx(), tile.drawy()); - - Draw.color(tile.entity.liquids.liquid.color); - Draw.alpha(tile.entity.liquids.amount / liquidCapacity); - Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); - Draw.color(); - } + @Override + public void load(){ + super.load(); - @Override - public TextureRegion[] getIcon(){ - return new TextureRegion[]{Draw.region(name)}; - } + liquidRegion = Draw.region("pump-liquid"); + } - @Override - public boolean canPlaceOn(Tile tile) { - if(isMultiblock()){ - Liquid last = null; - for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){ - //can't place pump on block with multiple liquids - if(last != null && other.floor().liquidDrop != last){ - return false; - } + @Override + public void setStats(){ + super.setStats(); + stats.add(BlockStat.liquidOutput, 60f * pumpAmount, StatUnit.liquidSecond); + } - if(isValid(other)){ - last = other.floor().liquidDrop; - } - } - return last != null; - }else{ - return isValid(tile); - } - } - - @Override - public void update(Tile tile){ - float tiles = 0f; - Liquid liquidDrop = null; + @Override + public void draw(Tile tile){ + Draw.rect(name(), tile.drawx(), tile.drawy()); - if(isMultiblock()){ - for(Tile other : tile.getLinkedTiles(updateTiles)){ - if(isValid(other)){ - liquidDrop = other.floor().liquidDrop; - tiles ++; - } - } - }else{ - tiles = 1f; - liquidDrop = tile.floor().liquidDrop; - } + Draw.color(tile.entity.liquids.current().color); + Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); + Draw.color(); + } - if(hasPower){ - float used = Math.min(powerCapacity, tiles * powerUse * Timers.delta()); + @Override + public TextureRegion[] getIcon(){ + return new TextureRegion[]{Draw.region(name)}; + } - //multiply liquid obtained by the fraction of power this pump has to pump it - //e.g. only has 50% power required = only pumps 50% of liquid that it can - tiles *= Mathf.clamp(tile.entity.power.amount / used); + @Override + public boolean canPlaceOn(Tile tile){ + if(isMultiblock()){ + Liquid last = null; + for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){ + //can't place pump on block with multiple liquids + if(last != null && other.floor().liquidDrop != last){ + return false; + } - tile.entity.power.amount -= Math.min(tile.entity.power.amount, used); - } + if(isValid(other)){ + last = other.floor().liquidDrop; + } + } + return last != null; + }else{ + return isValid(tile); + } + } - if(liquidDrop != null){ - float maxPump = Math.min(liquidCapacity - tile.entity.liquids.amount, tiles * pumpAmount * Timers.delta()); - tile.entity.liquids.liquid = liquidDrop; - tile.entity.liquids.amount += maxPump; - } + @Override + public void update(Tile tile){ + float tiles = 0f; + Liquid liquidDrop = null; - tryDumpLiquid(tile); - } + if(isMultiblock()){ + for(Tile other : tile.getLinkedTiles(updateTiles)){ + if(isValid(other)){ + liquidDrop = other.floor().liquidDrop; + tiles++; + } + } + }else{ + tiles = 1f; + liquidDrop = tile.floor().liquidDrop; + } - protected boolean isValid(Tile tile){ - return tile.floor().liquidDrop != null && tier >= tile.floor().liquidDrop.tier; - } + if(tile.entity.cons.valid() && liquidDrop != null){ + float maxPump = Math.min(liquidCapacity - tile.entity.liquids.total(), tiles * pumpAmount * Timers.delta()); + tile.entity.liquids.add(liquidDrop, maxPump); + } + + tryDumpLiquid(tile, tile.entity.liquids.current()); + } + + protected boolean isValid(Tile tile){ + return tile.floor().liquidDrop != null && tier >= tile.floor().liquidDrop.tier; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Separator.java b/core/src/io/anuke/mindustry/world/blocks/production/Separator.java index 4c3c981d69..583885d450 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Separator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Separator.java @@ -1,55 +1,61 @@ package io.anuke.mindustry.world.blocks.production; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import io.anuke.mindustry.content.Items; +import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.production.GenericCrafter.GenericCrafterEntity; import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.mindustry.world.meta.values.ItemFilterValue; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Mathf; -/**Extracts a random list of items from an input item and an input liquid.*/ -public class Separator extends Block { - protected final int timerDump = timers ++; +/** + * Extracts a random list of items from an input item and an input liquid. + */ +public class Separator extends Block{ + protected final int timerDump = timers++; - protected Liquid liquid; - protected Item item; protected Item[] results; - protected float liquidUse; - protected float powerUse; protected float filterTime; protected float spinnerRadius = 2.5f; protected float spinnerLength = 1f; protected float spinnerThickness = 1f; protected float spinnerSpeed = 2f; + protected Color color = Color.valueOf("858585"); + protected TextureRegion liquidRegion; + protected boolean offloading = false; - public Separator(String name) { + public Separator(String name){ super(name); update = true; solid = true; hasItems = true; hasLiquids = true; + + consumes.item(Items.stone); + consumes.liquid(Liquids.water, 0.1f); } @Override - public void setStats() { + public void load(){ + super.load(); + + liquidRegion = Draw.region(name + "-liquid"); + } + + @Override + public void setStats(){ super.setStats(); - if(hasPower){ - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); - } - - stats.add(BlockStat.liquidUse, liquidUse * 60f, StatUnit.liquidSecond); - stats.add(BlockStat.inputLiquid, liquid); stats.add(BlockStat.outputItem, new ItemFilterValue(item -> { for(Item i : results){ if(item == i) return true; @@ -59,36 +65,29 @@ public class Separator extends Block { } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ super.draw(tile); GenericCrafterEntity entity = tile.entity(); - Draw.color(tile.entity.liquids.liquid.color); - Draw.alpha(tile.entity.liquids.amount / liquidCapacity); - Draw.rect(name + "-liquid", tile.drawx(), tile.drawy()); + Draw.color(tile.entity.liquids.current().color); + Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); - Draw.color(Color.valueOf("858585")); + Draw.color(color); Lines.stroke(spinnerThickness); - Lines.spikes(tile.drawx(), tile.drawy(), spinnerRadius, spinnerLength, 3, entity.totalProgress*spinnerSpeed); + Lines.spikes(tile.drawx(), tile.drawy(), spinnerRadius, spinnerLength, 3, entity.totalProgress * spinnerSpeed); Draw.reset(); } @Override - public void update(Tile tile) { + public void update(Tile tile){ GenericCrafterEntity entity = tile.entity(); - float liquidUsed = Math.min(liquidCapacity, liquidUse * Timers.delta()); - float powerUsed = Math.min(powerCapacity, powerUse * Timers.delta()); - - entity.totalProgress += entity.warmup*Timers.delta(); - - if(entity.liquids.amount >= liquidUsed && entity.items.hasItem(item) && - (!hasPower || entity.power.amount >= powerUsed)){ - entity.progress += 1f/filterTime; - entity.liquids.amount -= liquidUsed; - if(hasPower) entity.power.amount -= powerUsed; + entity.totalProgress += entity.warmup * Timers.delta(); + if(entity.cons.valid()){ + entity.progress += 1f / filterTime; entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.02f); @@ -97,7 +96,7 @@ public class Separator extends Block { if(entity.progress >= 1f){ entity.progress = 0f; Item item = Mathf.select(results); - entity.items.removeItem(this.item, 1); + entity.items.remove(consumes.item(), consumes.itemAmount()); if(item != null){ offloading = true; offloadNear(tile, item); @@ -111,22 +110,12 @@ public class Separator extends Block { } @Override - public boolean canDump(Tile tile, Tile to, Item item) { - return offloading || item != this.item; + public boolean canDump(Tile tile, Tile to, Item item){ + return offloading || item != consumes.item(); } @Override - public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) { - return super.acceptLiquid(tile, source, liquid, amount) && this.liquid == liquid; - } - - @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return this.item == item && tile.entity.items.getItem(item) < itemCapacity; - } - - @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new GenericCrafterEntity(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Smelter.java b/core/src/io/anuke/mindustry/world/blocks/production/Smelter.java index 303aded079..1f347070d9 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Smelter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Smelter.java @@ -8,10 +8,11 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.consumers.ConsumeItem; +import io.anuke.mindustry.world.consumers.ConsumeItems; import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; -import io.anuke.mindustry.world.meta.values.ItemListValue; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; @@ -20,170 +21,169 @@ import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.util.Mathf; public class Smelter extends Block{ - protected final int timerDump = timers++; - protected final int timerCraft = timers++; - - protected ItemStack[] inputs; - protected Item fuel; - protected Item result; + protected final int timerDump = timers++; + protected final int timerCraft = timers++; - protected float minFlux = 0.2f; - protected float baseFluxChance = 0.15f; - protected boolean useFlux = false; + protected Item result; - protected float craftTime = 20f; - protected float burnDuration = 50f; - protected Effect craftEffect = BlockFx.smelt, burnEffect = BlockFx.fuelburn; - protected Color flameColor = Color.valueOf("ffb879"); + protected float minFlux = 0.2f; + protected float baseFluxChance = 0.15f; + protected boolean useFlux = false; - public Smelter(String name) { - super(name); - update = true; - hasItems = true; - solid = true; - itemCapacity = 20; - } + protected float craftTime = 20f; + protected float burnDuration = 50f; + protected Effect craftEffect = BlockFx.smelt, burnEffect = BlockFx.fuelburn; + protected Color flameColor = Color.valueOf("ffb879"); - @Override - public void setBars(){ - for(ItemStack item : inputs){ - bars.add(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity.items.getItem(item.item)/itemCapacity)); - } - } - - @Override - public void setStats(){ - super.setStats(); + public Smelter(String name){ + super(name); + update = true; + hasItems = true; + solid = true; + itemCapacity = 20; - stats.add(BlockStat.inputFuel, fuel); - stats.add(BlockStat.fuelBurnTime, burnDuration/60f, StatUnit.seconds); - stats.add(BlockStat.inputItems, new ItemListValue(inputs)); - stats.add(BlockStat.outputItem, result); - stats.add(BlockStat.craftSpeed, 60f/craftTime, StatUnit.itemsSecond); - stats.add(BlockStat.inputItemCapacity, itemCapacity, StatUnit.items); - stats.add(BlockStat.outputItemCapacity, itemCapacity, StatUnit.items); - } + consumes.require(ConsumeItems.class); + consumes.require(ConsumeItem.class); + } - @Override - public void init() { - super.init(); + @Override + public void setBars(){ + for(ItemStack item : consumes.items()){ + bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.get(item.item) / itemCapacity)); + } + } - for(ItemStack item : inputs){ - if(item.item.fluxiness >= minFlux && useFlux){ - throw new IllegalArgumentException("'" + name + "' has input item '" + item.item.name + "', which is a flux, when useFlux is enabled. To prevent ambiguous item use, either remove this flux item from the inputs, or set useFlux to false."); - } - } - } + @Override + public void setStats(){ + super.setStats(); - @Override - public void update(Tile tile){ - SmelterEntity entity = tile.entity(); - - if(entity.timer.get(timerDump, 5) && entity.items.hasItem(result)){ - tryDump(tile, result); - } + //TODO + //stats.add(BlockStat.inputFuel, fuel); + stats.add(BlockStat.fuelBurnTime, burnDuration / 60f, StatUnit.seconds); + stats.add(BlockStat.outputItem, result); + stats.add(BlockStat.craftSpeed, 60f / craftTime, StatUnit.itemsSecond); + stats.add(BlockStat.inputItemCapacity, itemCapacity, StatUnit.items); + stats.add(BlockStat.outputItemCapacity, itemCapacity, StatUnit.items); + } - //add fuel - if(entity.items.getItem(fuel) > 0 && entity.burnTime <= 0f){ - entity.items.removeItem(fuel, 1); - entity.burnTime += burnDuration; - Effects.effect(burnEffect, entity.x + Mathf.range(2f), entity.y + Mathf.range(2f)); - } + @Override + public void init(){ + super.init(); - //decrement burntime - if(entity.burnTime > 0){ - entity.burnTime -= Timers.delta(); - entity.heat = Mathf.lerp(entity.heat, 1f, 0.02f); - }else{ - entity.heat = Mathf.lerp(entity.heat, 0f, 0.02f); - } + for(ItemStack item : consumes.items()){ + if(item.item.fluxiness >= minFlux && useFlux){ + throw new IllegalArgumentException("'" + name + "' has input item '" + item.item.name + "', which is a flux, when useFlux is enabled. To prevent ambiguous item use, either remove this flux item from the inputs, or set useFlux to false."); + } + } + } - //make sure it has all the items - for(ItemStack item : inputs){ - if(!entity.items.hasItem(item.item, item.amount)){ - return; - } - } + @Override + public void update(Tile tile){ + SmelterEntity entity = tile.entity(); - if(entity.items.getItem(result) >= itemCapacity //output full - || entity.burnTime <= 0 //not burning - || !entity.timer.get(timerCraft, craftTime)){ //not yet time - return; - } + if(entity.timer.get(timerDump, 5) && entity.items.has(result)){ + tryDump(tile, result); + } - boolean consumeInputs = true; + //add fuel + if(entity.consumed(ConsumeItem.class) && entity.burnTime <= 0f){ + entity.items.remove(consumes.item(), 1); + entity.burnTime += burnDuration; + Effects.effect(burnEffect, entity.x + Mathf.range(2f), entity.y + Mathf.range(2f)); + } - if(useFlux){ - //remove flux materials if present - for(Item item : Item.all()){ - if(item.fluxiness >= minFlux && tile.entity.items.getItem(item) > 0){ - tile.entity.items.removeItem(item, 1); + //decrement burntime + if(entity.burnTime > 0){ + entity.burnTime -= Timers.delta(); + entity.heat = Mathf.lerp(entity.heat, 1f, 0.02f); + }else{ + entity.heat = Mathf.lerp(entity.heat, 0f, 0.02f); + } - //chance of not consuming inputs if flux material present - consumeInputs = !Mathf.chance(item.fluxiness * baseFluxChance); - break; - } - } - } + //make sure it has all the items + if(!entity.cons.valid()){ + return; + } - if(consumeInputs) { - for (ItemStack item : inputs) { - entity.items.removeItem(item.item, item.amount); - } - } - - offloadNear(tile, result); - Effects.effect(craftEffect, flameColor, tile.drawx(), tile.drawy()); - } + if(entity.items.get(result) >= itemCapacity //output full + || entity.burnTime <= 0 //not burning + || !entity.timer.get(timerCraft, craftTime)){ //not yet time + return; + } - @Override - public int getMaximumAccepted(Tile tile, Item item) { - return itemCapacity - tile.entity.items.getItem(item); - } + boolean consumeInputs = true; - @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - boolean isInput = false; + if(useFlux){ + //remove flux materials if present + for(Item item : Item.all()){ + if(item.fluxiness >= minFlux && tile.entity.items.get(item) > 0){ + tile.entity.items.remove(item, 1); - for(ItemStack req : inputs){ - if(req.item == item){ - isInput = true; - break; - } - } + //chance of not consuming inputs if flux material present + consumeInputs = !Mathf.chance(item.fluxiness * baseFluxChance); + break; + } + } + } - return (isInput && tile.entity.items.getItem(item) < itemCapacity) || (item == fuel && tile.entity.items.getItem(fuel) < itemCapacity) || - (useFlux && item.fluxiness >= minFlux && tile.entity.items.getItem(item) < itemCapacity); - } + if(consumeInputs){ + for(ItemStack item : consumes.items()){ + entity.items.remove(item.item, item.amount); + } + } - @Override - public void draw(Tile tile){ - super.draw(tile); + offloadNear(tile, result); + Effects.effect(craftEffect, flameColor, tile.drawx(), tile.drawy()); + } + + @Override + public int getMaximumAccepted(Tile tile, Item item){ + return itemCapacity - tile.entity.items.get(item); + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + boolean isInput = false; + + for(ItemStack req : consumes.items()){ + if(req.item == item){ + isInput = true; + break; + } + } + + return (isInput && tile.entity.items.get(item) < itemCapacity) || (item == consumes.item() && tile.entity.items.get(consumes.item()) < itemCapacity) || + (useFlux && item.fluxiness >= minFlux && tile.entity.items.get(item) < itemCapacity); + } + + @Override + public void draw(Tile tile){ + super.draw(tile); SmelterEntity entity = tile.entity(); //draw glowing center - if(entity.heat > 0f){ - float g = 0.1f; + if(entity.heat > 0f){ + float g = 0.1f; - Draw.alpha(((1f-g) + Mathf.absin(Timers.time(), 8f, g)) * entity.heat); + Draw.alpha(((1f - g) + Mathf.absin(Timers.time(), 8f, g)) * entity.heat); - Draw.tint(flameColor); - Fill.circle(tile.drawx(), tile.drawy(), 2f + Mathf.absin(Timers.time(), 5f, 0.8f)); - Draw.color(1f, 1f, 1f, entity.heat); - Fill.circle(tile.drawx(), tile.drawy(), 1f + Mathf.absin(Timers.time(), 5f, 0.7f)); + Draw.tint(flameColor); + Fill.circle(tile.drawx(), tile.drawy(), 2f + Mathf.absin(Timers.time(), 5f, 0.8f)); + Draw.color(1f, 1f, 1f, entity.heat); + Fill.circle(tile.drawx(), tile.drawy(), 1f + Mathf.absin(Timers.time(), 5f, 0.7f)); - Draw.color(); - } + Draw.color(); + } } - @Override - public TileEntity getEntity() { - return new SmelterEntity(); - } + @Override + public TileEntity getEntity(){ + return new SmelterEntity(); + } - public class SmelterEntity extends TileEntity{ - public float burnTime; - public float heat; - } + public class SmelterEntity extends TileEntity{ + public float burnTime; + public float heat; + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java b/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java index a15ff7c5ea..49523b350b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java @@ -7,18 +7,17 @@ import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; -/**Pump that makes liquid from solids and takes in power. Only works on solid floor blocks.*/ -public class SolidPump extends Pump { +/** + * Pump that makes liquid from solids and takes in power. Only works on solid floor blocks. + */ +public class SolidPump extends Pump{ protected Liquid result = Liquids.water; - /**Power use per liquid unit.*/ - protected float powerUse = 0.1f; protected Effect updateEffect = Fx.none; protected float updateEffectChance = 0.02f; protected float rotateSpeed = 1f; @@ -26,26 +25,30 @@ public class SolidPump extends Pump { public SolidPump(String name){ super(name); hasPower = true; - liquidRegion = name + "-liquid"; } @Override - public void setStats() { + public void load(){ + super.load(); + + liquidRegion = Draw.region(name + "-liquid"); + } + + @Override + public void setStats(){ super.setStats(); stats.remove(BlockStat.liquidOutput); - - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); stats.add(BlockStat.liquidOutput, result); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ SolidPumpEntity entity = tile.entity(); - Draw.rect(name, tile.drawx(), tile.drawy()); - Draw.color(tile.entity.liquids.liquid.color); - Draw.alpha(tile.entity.liquids.amount / liquidCapacity); + Draw.rect(region, tile.drawx(), tile.drawy()); + Draw.color(tile.entity.liquids.current().color); + Draw.alpha(tile.entity.liquids.total() / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); Draw.rect(name + "-rotator", tile.drawx(), tile.drawy(), entity.pumpTime * rotateSpeed); @@ -53,7 +56,7 @@ public class SolidPump extends Pump { } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ return new TextureRegion[]{Draw.region(name), Draw.region(name + "-rotator"), Draw.region(name + "-top")}; } @@ -61,39 +64,35 @@ public class SolidPump extends Pump { public void update(Tile tile){ SolidPumpEntity entity = tile.entity(); - float used = Math.min(powerUse * Timers.delta(), powerCapacity); - float fraction = 0f; if(isMultiblock()){ for(Tile other : tile.getLinkedTiles(tempTiles)){ if(isValid(other)){ - fraction += 1f/ size; + fraction += 1f / size; } } }else{ if(isValid(tile)) fraction = 1f; } - if(tile.entity.power.amount >= used && tile.entity.liquids.amount < liquidCapacity - 0.001f){ - float maxPump = Math.min(liquidCapacity - tile.entity.liquids.amount, pumpAmount * Timers.delta() * fraction); - tile.entity.liquids.liquid = result; - tile.entity.liquids.amount += maxPump; - tile.entity.power.amount -= used; + if(tile.entity.cons.valid() && typeLiquid(tile) < liquidCapacity - 0.001f){ + float maxPump = Math.min(liquidCapacity - typeLiquid(tile), pumpAmount * Timers.delta() * fraction); + tile.entity.liquids.add(result, maxPump); entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); if(Mathf.chance(Timers.delta() * updateEffectChance)) - Effects.effect(updateEffect, entity.x + Mathf.range(size*2f), entity.y + Mathf.range(size*2f)); + Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.02f); } entity.pumpTime += entity.warmup * Timers.delta(); - tryDumpLiquid(tile); + tryDumpLiquid(tile, result); } @Override - public boolean canPlaceOn(Tile tile) { + public boolean canPlaceOn(Tile tile){ if(isMultiblock()){ for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){ if(isValid(other)){ @@ -112,10 +111,14 @@ public class SolidPump extends Pump { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new SolidPumpEntity(); } + public float typeLiquid(Tile tile){ + return tile.entity.liquids.total(); + } + public static class SolidPumpEntity extends TileEntity{ public float warmup; public float pumpTime; diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java index ea0189c6ef..9d921ccc5a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java @@ -39,20 +39,20 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.*; -public class CoreBlock extends StorageBlock { +public class CoreBlock extends StorageBlock{ private static Rectangle rect = new Rectangle(); - protected int timerSupply = timers ++; + protected int timerSupply = timers++; protected float supplyRadius = 50f; protected float supplyInterval = 5f; - protected float droneRespawnDuration = 60*6; + protected float droneRespawnDuration = 60 * 6; protected UnitType droneType = UnitTypes.drone; protected TextureRegion openRegion; protected TextureRegion topRegion; - public CoreBlock(String name) { + public CoreBlock(String name){ super(name); solid = false; @@ -66,15 +66,37 @@ public class CoreBlock extends StorageBlock { flags = EnumSet.of(BlockFlag.resupplyPoint, BlockFlag.target); } + @Remote(called = Loc.server, in = In.blocks) + public static void onUnitRespawn(Tile tile, Unit player){ + if(player == null) return; + + CoreEntity entity = tile.entity(); + Effects.effect(Fx.spawn, entity); + entity.solid = false; + entity.progress = 0; + entity.currentUnit = player; + entity.currentUnit.heal(); + entity.currentUnit.rotation = 90f; + entity.currentUnit.setNet(tile.drawx(), tile.drawy()); + entity.currentUnit.add(); + entity.currentUnit = null; + } + + @Remote(called = Loc.server, in = In.blocks) + public static void setCoreSolid(Tile tile, boolean solid){ + CoreEntity entity = tile.entity(); + entity.solid = solid; + } + @Override - public void setBars() { + public void setBars(){ super.setBars(); bars.remove(BarType.inventory); } @Override - public void load() { + public void load(){ super.load(); openRegion = Draw.region(name + "-open"); @@ -82,12 +104,12 @@ public class CoreBlock extends StorageBlock { } @Override - public float handleDamage(Tile tile, float amount) { + public float handleDamage(Tile tile, float amount){ return debug ? 0 : amount; } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ CoreEntity entity = tile.entity(); Draw.rect(entity.solid ? Draw.region(name) : openRegion, tile.drawx(), tile.drawy()); @@ -96,7 +118,7 @@ public class CoreBlock extends StorageBlock { Draw.rect(topRegion, tile.drawx(), tile.drawy()); Draw.color(); - if(entity.currentUnit != null) { + if(entity.currentUnit != null){ Unit player = entity.currentUnit; TextureRegion region = player.getIconRegion(); @@ -117,14 +139,14 @@ public class CoreBlock extends StorageBlock { tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size), tile.drawy(), 90, - size * Vars.tilesize /2f); + size * Vars.tilesize / 2f); Draw.reset(); } } @Override - public boolean isSolidFor(Tile tile) { + public boolean isSolidFor(Tile tile){ CoreEntity entity = tile.entity(); return entity.solid; @@ -133,15 +155,15 @@ public class CoreBlock extends StorageBlock { @Override public int acceptStack(Item item, int amount, Tile tile, Unit source){ if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){ - return Math.min(itemCapacity - tile.entity.items.getItem(item), amount); + return Math.min(itemCapacity - tile.entity.items.get(item), amount); }else{ return 0; } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return tile.entity.items.items[item.id] < itemCapacity && item.type == ItemType.material; + public boolean acceptItem(Item item, Tile tile, Tile source){ + return tile.entity.items.get(item) < itemCapacity && item.type == ItemType.material; } @Override @@ -167,7 +189,7 @@ public class CoreBlock extends StorageBlock { } @Override - public void update(Tile tile) { + public void update(Tile tile){ CoreEntity entity = tile.entity(); if(!entity.solid && !Units.anyEntities(tile)){ @@ -215,15 +237,16 @@ public class CoreBlock extends StorageBlock { } if(entity.solid && tile.entity.timer.get(timerSupply, supplyInterval)){ - rect.setSize(supplyRadius*2).setCenter(tile.drawx(), tile.drawy()); + rect.setSize(supplyRadius * 2).setCenter(tile.drawx(), tile.drawy()); Units.getNearby(tile.getTeam(), rect, unit -> { - if(unit.isDead() || unit.distanceTo(tile.drawx(), tile.drawy()) > supplyRadius || unit.getGroup() == null) return; + if(unit.isDead() || unit.distanceTo(tile.drawx(), tile.drawy()) > supplyRadius || unit.getGroup() == null) + return; - for(int i = 0; i < tile.entity.items.items.length; i ++){ + for(int i = 0; i < Item.all().size; i++){ Item item = Item.getByID(i); - if(tile.entity.items.items[i] > 0 && unit.acceptsAmmo(item)){ - tile.entity.items.items[i] --; + if(tile.entity.items.get(item) > 0 && unit.acceptsAmmo(item)){ + tile.entity.items.remove(item, 1); unit.addAmmo(item); CallEntity.transferAmmo(item, tile.drawx(), tile.drawy(), unit); return; @@ -234,44 +257,23 @@ public class CoreBlock extends StorageBlock { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new CoreEntity(); } - @Remote(called = Loc.server, in = In.blocks) - public static void onUnitRespawn(Tile tile, Unit player){ - if(player == null) return; + /* + @Remote(called = Loc.server, in = In.blocks) + public static void onCoreUnitSet(Tile tile, Unit player){ + CoreEntity entity = tile.entity(); + entity.currentUnit = player; + entity.progress = 0f; + player.set(tile.drawx(), tile.drawy()); - CoreEntity entity = tile.entity(); - Effects.effect(Fx.spawn, entity); - entity.solid = false; - entity.progress = 0; - entity.currentUnit = player; - entity.currentUnit.heal(); - entity.currentUnit.rotation = 90f; - entity.currentUnit.setNet(tile.drawx(), tile.drawy()); - entity.currentUnit.add(); - entity.currentUnit = null; - } - - @Remote(called = Loc.server, in = In.blocks) - public static void setCoreSolid(Tile tile, boolean solid){ - CoreEntity entity = tile.entity(); - entity.solid = solid; - } -/* - @Remote(called = Loc.server, in = In.blocks) - public static void onCoreUnitSet(Tile tile, Unit player){ - CoreEntity entity = tile.entity(); - entity.currentUnit = player; - entity.progress = 0f; - player.set(tile.drawx(), tile.drawy()); - - if(player instanceof Player){ - ((Player) player).setRespawning(true); + if(player instanceof Player){ + ((Player) player).setRespawning(true); + } } - } -*/ + */ public class CoreEntity extends TileEntity implements SpawnerTrait{ public Unit currentUnit; int droneID = -1; @@ -282,7 +284,7 @@ public class CoreBlock extends StorageBlock { float heat; @Override - public void updateSpawning(Unit unit) { + public void updateSpawning(Unit unit){ if(currentUnit == null){ currentUnit = unit; progress = 0f; @@ -291,18 +293,18 @@ public class CoreBlock extends StorageBlock { } @Override - public float getSpawnProgress() { + public float getSpawnProgress(){ return progress; } @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeBoolean(solid); stream.writeInt(droneID); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ solid = stream.readBoolean(); droneID = stream.readInt(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/SortedUnloader.java b/core/src/io/anuke/mindustry/world/blocks/storage/SortedUnloader.java index 7d65048455..00cf65918c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/SortedUnloader.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/SortedUnloader.java @@ -26,20 +26,26 @@ public class SortedUnloader extends Unloader implements SelectionTrait{ //TODO call event + @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) + public static void setSortedUnloaderItem(Player player, Tile tile, Item item){ + SortedUnloaderEntity entity = tile.entity(); + entity.sortItem = item; + } + @Override public void update(Tile tile){ SortedUnloaderEntity entity = tile.entity(); - if(entity.items.totalItems() == 0 && entity.timer.get(timerUnload, speed)){ + if(entity.items.total() == 0 && entity.timer.get(timerUnload, speed)){ tile.allNearby(other -> { - if(other.block() instanceof StorageBlock && entity.items.totalItems() == 0 && - ((StorageBlock)other.block()).hasItem(other, entity.sortItem)){ - offloadNear(tile, ((StorageBlock)other.block()).removeItem(other, entity.sortItem)); + if(other.block() instanceof StorageBlock && entity.items.total() == 0 && + ((StorageBlock) other.block()).hasItem(other, entity.sortItem)){ + offloadNear(tile, ((StorageBlock) other.block()).removeItem(other, entity.sortItem)); } }); } - if(entity.items.totalItems() > 0){ + if(entity.items.total() > 0){ tryDump(tile); } } @@ -66,17 +72,11 @@ public class SortedUnloader extends Unloader implements SelectionTrait{ return new SortedUnloaderEntity(); } - @Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true) - public static void setSortedUnloaderItem(Player player, Tile tile, Item item){ - SortedUnloaderEntity entity = tile.entity(); - entity.sortItem = item; - } - public static class SortedUnloaderEntity extends TileEntity{ public Item sortItem = Items.tungsten; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeByte(sortItem.id); } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java index f65cf710c6..b5e4c83a8c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java @@ -5,35 +5,42 @@ import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -public abstract class StorageBlock extends Block { +public abstract class StorageBlock extends Block{ public StorageBlock(String name){ super(name); hasItems = true; } - /**Removes an item and returns it. If item is not null, it should return the item. - * Returns null if no items are there.*/ + /** + * Removes an item and returns it. If item is not null, it should return the item. + * Returns null if no items are there. + */ public Item removeItem(Tile tile, Item item){ TileEntity entity = tile.entity; - for(int i = 0; i < entity.items.items.length; i ++){ - if(entity.items.items[i] > 0 && (item == null || i == item.id)){ - entity.items.items[i] --; - return Item.getByID(i); + + if(item == null){ + return entity.items.take(); + }else{ + if(entity.items.has(item)){ + entity.items.remove(item, 1); + return item; } + + return null; } - return null; } - /**Returns whether this storage block has the specified item. - * If the item is null, it should return whether it has ANY items.*/ + /** + * Returns whether this storage block has the specified item. + * If the item is null, it should return whether it has ANY items. + */ public boolean hasItem(Tile tile, Item item){ TileEntity entity = tile.entity; - for(int i = 0; i < entity.items.items.length; i ++){ - if(entity.items.items[i] > 0 && (item == null || i == item.id)){ - return true; - } + if(item == null){ + return entity.items.total() > 0; + }else{ + return entity.items.has(item); } - return false; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java b/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java index 71d801153e..6e7d32403c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java @@ -2,10 +2,10 @@ package io.anuke.mindustry.world.blocks.storage; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.meta.BlockGroup; -public class Unloader extends Block { +public class Unloader extends Block{ protected final int timerUnload = timers++; protected int speed = 5; @@ -20,26 +20,27 @@ public class Unloader extends Block { @Override public void update(Tile tile){ - if(tile.entity.items.totalItems() == 0 && tile.entity.timer.get(timerUnload, speed)){ + if(tile.entity.items.total() == 0 && tile.entity.timer.get(timerUnload, speed)){ tile.allNearby(other -> { - if(other.block() instanceof StorageBlock && tile.entity.items.totalItems() == 0 && - ((StorageBlock)other.block()).hasItem(other, null)){ - offloadNear(tile, ((StorageBlock)other.block()).removeItem(other, null)); + if(other.block() instanceof StorageBlock && tile.entity.items.total() == 0 && + ((StorageBlock) other.block()).hasItem(other, null)){ + offloadNear(tile, ((StorageBlock) other.block()).removeItem(other, null)); } }); } - if(tile.entity.items.totalItems() > 0){ + if(tile.entity.items.total() > 0){ tryDump(tile); } } @Override - public boolean canDump(Tile tile, Tile to, Item item) { + public boolean canDump(Tile tile, Tile to, Item item){ Block block = to.target().block(); return !(block instanceof StorageBlock); } @Override - public void setBars(){} + public void setBars(){ + } } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/Vault.java b/core/src/io/anuke/mindustry/world/blocks/storage/Vault.java index 314f22b0fc..16e23306ea 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/Vault.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/Vault.java @@ -4,7 +4,7 @@ import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.Timers; -public class Vault extends StorageBlock { +public class Vault extends StorageBlock{ public Vault(String name){ super(name); @@ -17,8 +17,8 @@ public class Vault extends StorageBlock { public void update(Tile tile){ int iterations = Math.max(1, (int) (Timers.delta() + 0.4f)); - for(int i = 0; i < iterations; i ++) { - if (tile.entity.items.totalItems() > 0) { + for(int i = 0; i < iterations; i++){ + if(tile.entity.items.total() > 0){ tryDump(tile); } } @@ -30,16 +30,16 @@ public class Vault extends StorageBlock { } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return tile.entity.items.totalItems() < itemCapacity; + public boolean acceptItem(Item item, Tile tile, Tile source){ + return tile.entity.items.total() < itemCapacity; } @Override - public boolean canDump(Tile tile, Tile to, Item item) { + public boolean canDump(Tile tile, Tile to, Item item){ to = to.target(); - if (!(to.block() instanceof StorageBlock)) return false; + if(!(to.block() instanceof StorageBlock)) return false; - return !(to.block() instanceof Vault) || (float) to.entity.items.totalItems() / to.block().itemCapacity < (float) tile.entity.items.totalItems() / itemCapacity; + return !(to.block() instanceof Vault) || (float) to.entity.items.total() / to.block().itemCapacity < (float) tile.entity.items.total() / itemCapacity; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java b/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java index 830b215b2d..c4a5ca3859 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java @@ -2,8 +2,8 @@ package io.anuke.mindustry.world.blocks.units; import io.anuke.mindustry.world.Block; -public class CommandCenter extends Block { - public CommandCenter(String name) { +public class CommandCenter extends Block{ + public CommandCenter(String name){ super(name); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/DropPoint.java b/core/src/io/anuke/mindustry/world/blocks/units/DropPoint.java index 1834531712..8acdf20be9 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/DropPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/DropPoint.java @@ -4,9 +4,9 @@ import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -public class DropPoint extends Block { +public class DropPoint extends Block{ - public DropPoint(String name) { + public DropPoint(String name){ super(name); hasItems = true; @@ -15,13 +15,13 @@ public class DropPoint extends Block { } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { + public boolean acceptItem(Item item, Tile tile, Tile source){ return false; } @Override - public void update(Tile tile) { - if (tile.entity.items.totalItems() > 0) { + public void update(Tile tile){ + if(tile.entity.items.total() > 0){ tryDump(tile); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/MechFactory.java b/core/src/io/anuke/mindustry/world/blocks/units/MechFactory.java index 99c54704cf..df2c2db165 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/MechFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/MechFactory.java @@ -33,7 +33,7 @@ import static io.anuke.mindustry.Vars.tilesize; public class MechFactory extends Block{ protected Mech mech; - protected float buildTime = 60*5; + protected float buildTime = 60 * 5; protected TextureRegion openRegion; @@ -44,14 +44,53 @@ public class MechFactory extends Block{ solidifes = true; } + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks) + public static void onMechFactoryTap(Player player, Tile tile){ + if(!checkValidTap(tile, player)) return; + + MechFactoryEntity entity = tile.entity(); + player.beginRespawning(entity); + } + + @Remote(called = Loc.server, in = In.blocks) + public static void onMechFactoryDone(Tile tile){ + MechFactoryEntity entity = tile.entity(); + + Effects.effect(Fx.spawn, entity); + + if(entity.player == null) return; + + Mech result = ((MechFactory) tile.block()).mech; + + if(entity.player.mech == result){ + entity.player.mech = (entity.player.isMobile ? Mechs.starterMobile : Mechs.starterDesktop); + }else{ + entity.player.mech = result; + } + + entity.progress = 0; + entity.player.heal(); + entity.open = true; + entity.player.setDead(false); + entity.player.inventory.clear(); + entity.player = null; + } + + protected static boolean checkValidTap(Tile tile, Player player){ + MechFactoryEntity entity = tile.entity(); + return Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize / 2f && + Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize / 2f && entity.player == null; + } + @Override - public boolean isSolidFor(Tile tile) { + public boolean isSolidFor(Tile tile){ MechFactoryEntity entity = tile.entity(); return !entity.open; } @Override - public void tapped(Tile tile, Player player) { + public void tapped(Tile tile, Player player){ + if(mobile && !mech.flying) return; if(checkValidTap(tile, player)){ CallBlocks.onMechFactoryTap(player, tile); @@ -61,18 +100,18 @@ public class MechFactory extends Block{ } @Override - public void load() { + public void load(){ super.load(); openRegion = Draw.region(name + "-open"); } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ MechFactoryEntity entity = tile.entity(); Draw.rect(entity.open ? openRegion : Draw.region(name), tile.drawx(), tile.drawy()); - if(entity.player != null) { + if(entity.player != null){ TextureRegion region = mech.iconRegion; if(entity.player.mech == mech){ @@ -102,7 +141,7 @@ public class MechFactory extends Block{ } @Override - public void update(Tile tile) { + public void update(Tile tile){ MechFactoryEntity entity = tile.entity(); if(entity.open){ @@ -132,48 +171,10 @@ public class MechFactory extends Block{ } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new MechFactoryEntity(); } - @Remote(targets = Loc.both, called = Loc.server, in = In.blocks) - public static void onMechFactoryTap(Player player, Tile tile){ - if(!checkValidTap(tile, player)) return; - - MechFactoryEntity entity = tile.entity(); - player.beginRespawning(entity); - } - - @Remote(called = Loc.server, in = In.blocks) - public static void onMechFactoryDone(Tile tile){ - MechFactoryEntity entity = tile.entity(); - - Effects.effect(Fx.spawn, entity); - - if(entity.player == null) return; - - Mech result = ((MechFactory)tile.block()).mech; - - if(entity.player.mech == result){ - entity.player.mech = (entity.player.isMobile ? Mechs.starterMobile : Mechs.starterDesktop); - }else{ - entity.player.mech = result; - } - - entity.progress = 0; - entity.player.heal(); - entity.open = true; - entity.player.setDead(false); - entity.player.inventory.clear(); - entity.player = null; - } - - protected static boolean checkValidTap(Tile tile, Player player){ - MechFactoryEntity entity = tile.entity(); - return Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize / 2f && - Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize / 2f && entity.player == null; - } - public class MechFactoryEntity extends TileEntity implements SpawnerTrait{ Player player; float progress; @@ -182,12 +183,13 @@ public class MechFactory extends Block{ boolean open; @Override - public void updateSpawning(Unit unit) { - if(!(unit instanceof Player)) throw new IllegalArgumentException("Mech factories only accept player respawners."); + public void updateSpawning(Unit unit){ + if(!(unit instanceof Player)) + throw new IllegalArgumentException("Mech factories only accept player respawners."); if(player == null){ progress = 0f; - player = (Player)unit; + player = (Player) unit; player.rotation = 90f; player.baseRotation = 90f; @@ -197,19 +199,19 @@ public class MechFactory extends Block{ } @Override - public float getSpawnProgress() { + public float getSpawnProgress(){ return progress; } @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeFloat(progress); stream.writeFloat(time); stream.writeFloat(heat); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ progress = stream.readFloat(); time = stream.readFloat(); heat = stream.readFloat(); diff --git a/core/src/io/anuke/mindustry/world/blocks/units/OverdriveProjector.java b/core/src/io/anuke/mindustry/world/blocks/units/OverdriveProjector.java index 7acecd1414..740f631053 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/OverdriveProjector.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/OverdriveProjector.java @@ -2,9 +2,9 @@ package io.anuke.mindustry.world.blocks.units; import io.anuke.mindustry.content.StatusEffects; -public class OverdriveProjector extends Projector { +public class OverdriveProjector extends Projector{ - public OverdriveProjector(String name) { + public OverdriveProjector(String name){ super(name); status = StatusEffects.overdrive; diff --git a/core/src/io/anuke/mindustry/world/blocks/units/Projector.java b/core/src/io/anuke/mindustry/world/blocks/units/Projector.java index 5dd6c7c3e5..0b05f77f7e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/Projector.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/Projector.java @@ -11,17 +11,16 @@ import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Mathf; -public abstract class Projector extends Block { +public abstract class Projector extends Block{ protected final int timerApply = timers++; protected final float applyTime = 4f; - protected float powerUse = 0.01f; protected float range = 80f; protected StatusEffect status; protected float intensity = 1f; - public Projector(String name) { + public Projector(String name){ super(name); hasPower = true; update = true; @@ -36,19 +35,16 @@ public abstract class Projector extends Block { } @Override - public void update(Tile tile) { + public void update(Tile tile){ ProjectorEntity entity = tile.entity(); - float used = Math.min(powerCapacity, powerUse * Timers.delta()); - - if(entity.power.amount >= used){ + if(entity.cons.valid()){ entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.01f); - entity.power.amount -= used; }else{ entity.heat = Mathf.lerpDelta(entity.heat, 0f, 0.01f); } - if(entity.heat > 0.6f && Timers.get(timerApply, applyTime)) { + if(entity.heat > 0.6f && Timers.get(timerApply, applyTime)){ Units.getNearby(tile.getTeam(), tile.drawx(), tile.drawy(), range, unit -> { unit.applyEffect(status, intensity); }); @@ -56,7 +52,7 @@ public abstract class Projector extends Block { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new ProjectorEntity(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/Reconstructor.java b/core/src/io/anuke/mindustry/world/blocks/units/Reconstructor.java index 3722567476..02e74a5f1e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/Reconstructor.java @@ -38,7 +38,7 @@ public class Reconstructor extends Block{ protected Effect arriveEffect = Fx.spawn; protected TextureRegion openRegion; - public Reconstructor(String name) { + public Reconstructor(String name){ super(name); update = true; solidifes = true; @@ -46,191 +46,11 @@ public class Reconstructor extends Block{ configurable = true; } - @Override - public void load() { - super.load(); - openRegion = Draw.region(name + "-open"); - } - - @Override - public boolean isSolidFor(Tile tile) { - ReconstructorEntity entity = tile.entity(); - - return entity.solid; - } - - @Override - public void drawConfigure(Tile tile) { - super.drawConfigure(tile); - - ReconstructorEntity entity = tile.entity(); - - if(validLink(tile, entity.link)){ - Tile target = world.tile(entity.link); - - Draw.color(Palette.place); - Lines.square(target.drawx(), target.drawy(), - target.block().size * tilesize / 2f + 1f); - Draw.reset(); - } - - Draw.color(Palette.accent); - Draw.color(); - } - - @Override - public boolean onConfigureTileTapped(Tile tile, Tile other){ - if(tile == other) return false; - - ReconstructorEntity entity = tile.entity(); - - if(entity.link == other.packedPosition()) { - CallBlocks.unlinkReconstructor(null, tile, other); - return false; - }else if(other.block() instanceof Reconstructor){ - CallBlocks.linkReconstructor(null, tile, other); - return false; - } - - return true; - } - - @Override - public boolean shouldShowConfigure(Tile tile, Player player) { - ReconstructorEntity entity = tile.entity(); - return !checkValidTap(tile, entity, player); - } - - @Override - public boolean shouldHideConfigure(Tile tile, Player player){ - ReconstructorEntity entity = tile.entity(); - return checkValidTap(tile, entity, player); - } - - @Override - public void draw(Tile tile) { - ReconstructorEntity entity = tile.entity(); - - if(entity.solid){ - Draw.rect(name, tile.drawx(), tile.drawy()); - }else{ - Draw.rect(openRegion, tile.drawx(), tile.drawy()); - } - - if(entity.current != null){ - float progress = entity.departing ? entity.updateTime : (1f - entity.updateTime); - - //Player player = entity.current; - - TextureRegion region = entity.current.getIconRegion(); - - Shaders.build.region = region; - Shaders.build.progress = progress; - Shaders.build.color.set(Palette.accent); - Shaders.build.time = -entity.time / 10f; - - Graphics.shader(Shaders.build, false); - Shaders.build.apply(); - Draw.rect(region, tile.drawx(), tile.drawy()); - Graphics.shader(); - - Draw.color(Palette.accent); - - Lines.lineAngleCenter( - tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size), - tile.drawy(), - 90, - size * Vars.tilesize /2f); - - Draw.reset(); - } - } - - @Override - public void update(Tile tile) { - ReconstructorEntity entity = tile.entity(); - - boolean stayOpen = false; - - if(entity.current != null){ - entity.time += Timers.delta(); - - entity.solid = true; - - if(entity.departing){ - //force respawn if there's suddenly nothing to link to - if(!validLink(tile, entity.link)){ - //entity.current.setRespawning(false); - return; - } - - ReconstructorEntity other = world.tile(entity.link).entity(); - - entity.updateTime -= Timers.delta()/departTime; - if(entity.updateTime <= 0f){ - //no power? death. - if(other.power.amount < powerPerTeleport){ - entity.current.setDead(true); - //entity.current.setRespawning(false); - entity.current = null; - return; - } - other.power.amount -= powerPerTeleport; - other.current = entity.current; - other.departing = false; - other.current.set(other.x, other.y); - other.updateTime = 1f; - entity.current = null; - } - }else{ //else, arriving - entity.updateTime -= Timers.delta()/arriveTime; - - if(entity.updateTime <= 0f){ - entity.solid = false; - entity.current.setDead(false); - - Effects.effect(arriveEffect, entity.current); - - entity.current = null; - } - } - - }else{ - - if (validLink(tile, entity.link)) { - Tile other = world.tile(entity.link); - if (other.entity.power.amount >= powerPerTeleport && Units.anyEntities(tile, 4f, unit -> unit.getTeam() == entity.getTeam() && unit instanceof Player) && - entity.power.amount >= powerPerTeleport) { - entity.solid = false; - stayOpen = true; - } - } - - if (!stayOpen && !entity.solid && !Units.anyEntities(tile)) { - entity.solid = true; - } - } - } - - @Override - public void tapped(Tile tile, Player player) { - ReconstructorEntity entity = tile.entity(); - - if(!checkValidTap(tile, entity, player)) return; - - CallBlocks.reconstructPlayer(player, tile); - } - - @Override - public TileEntity getEntity() { - return new ReconstructorEntity(); - } - protected static boolean checkValidTap(Tile tile, ReconstructorEntity entity, Player player){ return validLink(tile, entity.link) && Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize / 2f && Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize / 2f && - entity.current == null && entity.power.amount >= ((Reconstructor)tile.block()).powerPerTeleport; + entity.current == null && entity.power.amount >= ((Reconstructor) tile.block()).powerPerTeleport; } protected static boolean validLink(Tile tile, int position){ @@ -255,18 +75,19 @@ public class Reconstructor extends Block{ public static void reconstructPlayer(Player player, Tile tile){ ReconstructorEntity entity = tile.entity(); - if(!checkValidTap(tile, entity, player) || entity.power.amount < ((Reconstructor)tile.block()).powerPerTeleport) return; + if(!checkValidTap(tile, entity, player) || entity.power.amount < ((Reconstructor) tile.block()).powerPerTeleport) + return; entity.departing = true; entity.current = player; entity.solid = false; - entity.power.amount -= ((Reconstructor)tile.block()).powerPerTeleport; + entity.power.amount -= ((Reconstructor) tile.block()).powerPerTeleport; entity.updateTime = 1f; entity.set(tile.drawx(), tile.drawy()); player.rotation = 90f; player.baseRotation = 90f; player.setDead(true); - // player.setRespawning(true); + // player.setRespawning(true); //player.setRespawning(); } @@ -303,6 +124,186 @@ public class Reconstructor extends Block{ }); } + @Override + public void load(){ + super.load(); + openRegion = Draw.region(name + "-open"); + } + + @Override + public boolean isSolidFor(Tile tile){ + ReconstructorEntity entity = tile.entity(); + + return entity.solid; + } + + @Override + public void drawConfigure(Tile tile){ + super.drawConfigure(tile); + + ReconstructorEntity entity = tile.entity(); + + if(validLink(tile, entity.link)){ + Tile target = world.tile(entity.link); + + Draw.color(Palette.place); + Lines.square(target.drawx(), target.drawy(), + target.block().size * tilesize / 2f + 1f); + Draw.reset(); + } + + Draw.color(Palette.accent); + Draw.color(); + } + + @Override + public boolean onConfigureTileTapped(Tile tile, Tile other){ + if(tile == other) return false; + + ReconstructorEntity entity = tile.entity(); + + if(entity.link == other.packedPosition()){ + CallBlocks.unlinkReconstructor(null, tile, other); + return false; + }else if(other.block() instanceof Reconstructor){ + CallBlocks.linkReconstructor(null, tile, other); + return false; + } + + return true; + } + + @Override + public boolean shouldShowConfigure(Tile tile, Player player){ + ReconstructorEntity entity = tile.entity(); + return !checkValidTap(tile, entity, player); + } + + @Override + public boolean shouldHideConfigure(Tile tile, Player player){ + ReconstructorEntity entity = tile.entity(); + return checkValidTap(tile, entity, player); + } + + @Override + public void draw(Tile tile){ + ReconstructorEntity entity = tile.entity(); + + if(entity.solid){ + Draw.rect(region, tile.drawx(), tile.drawy()); + }else{ + Draw.rect(openRegion, tile.drawx(), tile.drawy()); + } + + if(entity.current != null){ + float progress = entity.departing ? entity.updateTime : (1f - entity.updateTime); + + //Player player = entity.current; + + TextureRegion region = entity.current.getIconRegion(); + + Shaders.build.region = region; + Shaders.build.progress = progress; + Shaders.build.color.set(Palette.accent); + Shaders.build.time = -entity.time / 10f; + + Graphics.shader(Shaders.build, false); + Shaders.build.apply(); + Draw.rect(region, tile.drawx(), tile.drawy()); + Graphics.shader(); + + Draw.color(Palette.accent); + + Lines.lineAngleCenter( + tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size), + tile.drawy(), + 90, + size * Vars.tilesize / 2f); + + Draw.reset(); + } + } + + @Override + public void update(Tile tile){ + ReconstructorEntity entity = tile.entity(); + + boolean stayOpen = false; + + if(entity.current != null){ + entity.time += Timers.delta(); + + entity.solid = true; + + if(entity.departing){ + //force respawn if there's suddenly nothing to link to + if(!validLink(tile, entity.link)){ + //entity.current.setRespawning(false); + return; + } + + ReconstructorEntity other = world.tile(entity.link).entity(); + + entity.updateTime -= Timers.delta() / departTime; + if(entity.updateTime <= 0f){ + //no power? death. + if(other.power.amount < powerPerTeleport){ + entity.current.setDead(true); + //entity.current.setRespawning(false); + entity.current = null; + return; + } + other.power.amount -= powerPerTeleport; + other.current = entity.current; + other.departing = false; + other.current.set(other.x, other.y); + other.updateTime = 1f; + entity.current = null; + } + }else{ //else, arriving + entity.updateTime -= Timers.delta() / arriveTime; + + if(entity.updateTime <= 0f){ + entity.solid = false; + entity.current.setDead(false); + + Effects.effect(arriveEffect, entity.current); + + entity.current = null; + } + } + + }else{ + + if(validLink(tile, entity.link)){ + Tile other = world.tile(entity.link); + if(other.entity.power.amount >= powerPerTeleport && Units.anyEntities(tile, 4f, unit -> unit.getTeam() == entity.getTeam() && unit instanceof Player) && + entity.power.amount >= powerPerTeleport){ + entity.solid = false; + stayOpen = true; + } + } + + if(!stayOpen && !entity.solid && !Units.anyEntities(tile)){ + entity.solid = true; + } + } + } + + @Override + public void tapped(Tile tile, Player player){ + ReconstructorEntity entity = tile.entity(); + + if(!checkValidTap(tile, entity, player)) return; + + CallBlocks.reconstructPlayer(player, tile); + } + + @Override + public TileEntity getEntity(){ + return new ReconstructorEntity(); + } + public class ReconstructorEntity extends TileEntity implements SpawnerTrait{ Unit current; float updateTime; @@ -311,22 +312,22 @@ public class Reconstructor extends Block{ boolean solid = true, departing; @Override - public void updateSpawning(Unit unit) { + public void updateSpawning(Unit unit){ } @Override - public float getSpawnProgress() { + public float getSpawnProgress(){ return 0; } @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeInt(link); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ link = stream.readInt(); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java b/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java index 2d314ddd0a..e2e152509e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java @@ -9,8 +9,8 @@ import io.anuke.mindustry.entities.Units; import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; @@ -22,15 +22,14 @@ import io.anuke.ucore.util.Mathf; public class RepairPoint extends Block{ private static Rectangle rect = new Rectangle(); - protected int timerTarget = timers ++; + protected int timerTarget = timers++; protected float repairRadius = 50f; protected float repairSpeed = 0.3f; - protected float powerUsage = 0.2f; protected TextureRegion topRegion; - public RepairPoint(String name) { + public RepairPoint(String name){ super(name); update = true; solid = true; @@ -39,10 +38,11 @@ public class RepairPoint extends Block{ layer2 = Layer.laser; hasPower = true; powerCapacity = 20f; + consumes.power(0.06f); } @Override - public void load() { + public void load(){ super.load(); topRegion = Draw.region(name + "-turret"); @@ -56,14 +56,14 @@ public class RepairPoint extends Block{ } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ RepairPointEntity entity = tile.entity(); Draw.rect(topRegion, tile.drawx(), tile.drawy(), entity.rotation - 90); } @Override - public void drawLayer2(Tile tile) { + public void drawLayer2(Tile tile){ RepairPointEntity entity = tile.entity(); if(entity.target != null && @@ -80,11 +80,11 @@ public class RepairPoint extends Block{ } @Override - public void update(Tile tile) { + public void update(Tile tile){ RepairPointEntity entity = tile.entity(); if(entity.target != null && (entity.target.isDead() || entity.target.distanceTo(tile) > repairRadius || - entity.target.health >= entity.target.maxHealth())){ + entity.target.health >= entity.target.maxHealth())){ entity.target = null; }else if(entity.target != null){ entity.target.health += repairSpeed * Timers.delta() * entity.strength; @@ -92,16 +92,13 @@ public class RepairPoint extends Block{ entity.rotation = Mathf.slerpDelta(entity.rotation, entity.angleTo(entity.target), 0.5f); } - float powerUse = Math.min(Timers.delta() * powerUsage, powerCapacity); - - if(entity.target != null && entity.power.amount >= powerUse){ - entity.power.amount -= powerUse; + if(entity.target != null && entity.cons.valid()){ entity.strength = Mathf.lerpDelta(entity.strength, 1f, 0.08f * Timers.delta()); }else{ entity.strength = Mathf.lerpDelta(entity.strength, 0f, 0.07f * Timers.delta()); } - if(entity.timer.get(timerTarget, 20)) { + if(entity.timer.get(timerTarget, 20)){ rect.setSize(repairRadius * 2).setCenter(tile.drawx(), tile.drawy()); entity.target = Units.getClosest(tile.getTeam(), tile.drawx(), tile.drawy(), repairRadius, unit -> unit.health < unit.maxHealth()); @@ -109,7 +106,14 @@ public class RepairPoint extends Block{ } @Override - public TileEntity getEntity() { + public boolean shouldConsume(Tile tile){ + RepairPointEntity entity = tile.entity(); + + return entity.target != null; + } + + @Override + public TileEntity getEntity(){ return new RepairPointEntity(); } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/ResupplyPoint.java b/core/src/io/anuke/mindustry/world/blocks/units/ResupplyPoint.java index 7c2e6177a7..12aa4b3ce6 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/ResupplyPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/ResupplyPoint.java @@ -9,8 +9,8 @@ import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.meta.BlockFlag; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; @@ -22,14 +22,13 @@ import io.anuke.ucore.util.Mathf; public class ResupplyPoint extends Block{ private static Rectangle rect = new Rectangle(); - protected int timerSupply = timers ++; - protected int timerTarget = timers ++; + protected int timerSupply = timers++; + protected int timerTarget = timers++; protected float supplyRadius = 50f; protected float supplyInterval = 10f; - protected float powerUsage = 0.2f; - public ResupplyPoint(String name) { + public ResupplyPoint(String name){ super(name); update = true; solid = true; @@ -38,6 +37,8 @@ public class ResupplyPoint extends Block{ hasItems = true; hasPower = true; powerCapacity = 20f; + + consumes.power(0.02f); } @Override @@ -48,7 +49,7 @@ public class ResupplyPoint extends Block{ } @Override - public void drawLayer(Tile tile) { + public void drawLayer(Tile tile){ ResupplyPointEntity entity = tile.entity(); if(entity.strength > 0f){ @@ -64,11 +65,11 @@ public class ResupplyPoint extends Block{ x1, y1, entity.lastx, entity.lasty, entity.strength); Draw.color(Palette.accent); - for(int i = 0; i < dstTo/space-1; i ++){ - float fract = (i * space) / dstTo + ((Timers.time()/90f) % (space/dstTo)); - Draw.alpha(Mathf.clamp(fract*1.5f)); - Draw.rect("transfer-arrow", x1 + fract*xf, y1 + fract*yf, - 8, 8*entity.strength, ang); + for(int i = 0; i < dstTo / space - 1; i++){ + float fract = (i * space) / dstTo + ((Timers.time() / 90f) % (space / dstTo)); + Draw.alpha(Mathf.clamp(fract * 1.5f)); + Draw.rect("transfer-arrow", x1 + fract * xf, y1 + fract * yf, + 8, 8 * entity.strength, ang); } Draw.color(); @@ -77,18 +78,18 @@ public class ResupplyPoint extends Block{ } @Override - public void update(Tile tile) { + public void update(Tile tile){ ResupplyPointEntity entity = tile.entity(); if(!validTarget(entity, entity.target) || entity.target.distanceTo(tile) > supplyRadius){ entity.target = null; }else if(entity.target != null && entity.strength > 0.5f){ - if(entity.timer.get(timerSupply, supplyInterval)) { - for (int i = 0; i < tile.entity.items.items.length; i++) { + if(entity.timer.get(timerSupply, supplyInterval)){ + for(int i = 0; i < Item.all().size; i++){ Item item = Item.getByID(i); - if (tile.entity.items.items[i] > 0 && entity.target.acceptsAmmo(item)) { - tile.entity.items.items[i]--; + if(tile.entity.items.has(item) && entity.target.acceptsAmmo(item)){ + tile.entity.items.remove(item, 1); entity.target.addAmmo(item); break; } @@ -98,10 +99,7 @@ public class ResupplyPoint extends Block{ entity.rotation = Mathf.slerpDelta(entity.rotation, entity.angleTo(entity.target), 0.5f); } - float powerUse = Math.min(Timers.delta() * powerUsage, powerCapacity); - - if(entity.target != null && entity.power.amount >= powerUse){ - entity.power.amount -= powerUse; + if(entity.target != null && entity.cons.valid()){ entity.lastx = entity.target.x; entity.lasty = entity.target.y; entity.strength = Mathf.lerpDelta(entity.strength, 1f, 0.08f * Timers.delta()); @@ -109,7 +107,7 @@ public class ResupplyPoint extends Block{ entity.strength = Mathf.lerpDelta(entity.strength, 0f, 0.08f * Timers.delta()); } - if(entity.timer.get(timerTarget, 20)) { + if(entity.timer.get(timerTarget, 20)){ rect.setSize(supplyRadius * 2).setCenter(tile.drawx(), tile.drawy()); entity.target = Units.getClosest(tile.getTeam(), tile.drawx(), tile.drawy(), supplyRadius, unit -> validTarget(entity, unit)); @@ -117,12 +115,12 @@ public class ResupplyPoint extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - return tile.entity.items.totalItems() < itemCapacity; + public boolean acceptItem(Item item, Tile tile, Tile source){ + return tile.entity.items.total() < itemCapacity; } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new ResupplyPointEntity(); } @@ -130,9 +128,9 @@ public class ResupplyPoint extends Block{ if(unit == null || unit.inventory.totalAmmo() >= unit.inventory.ammoCapacity() || unit.isDead()) return false; - for(int i = 0; i < entity.items.items.length; i ++) { + for(int i = 0; i < Item.all().size; i++){ Item item = Item.getByID(i); - if (entity.items.items[i] > 0 && unit.acceptsAmmo(item)) { + if(entity.items.has(item) && unit.acceptsAmmo(item)){ return true; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/ShieldProjector.java b/core/src/io/anuke/mindustry/world/blocks/units/ShieldProjector.java index 7f171fe193..aab518b7b1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/ShieldProjector.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/ShieldProjector.java @@ -2,9 +2,9 @@ package io.anuke.mindustry.world.blocks.units; import io.anuke.mindustry.content.StatusEffects; -public class ShieldProjector extends Projector { +public class ShieldProjector extends Projector{ - public ShieldProjector(String name) { + public ShieldProjector(String name){ super(name); status = StatusEffects.shielded; diff --git a/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java b/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java index d4fc03f531..98142a6972 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java @@ -19,11 +19,11 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.blocks.modules.InventoryModule; +import io.anuke.mindustry.world.consumers.ConsumeItems; import io.anuke.mindustry.world.meta.BlockBar; import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; -import io.anuke.mindustry.world.meta.values.ItemListValue; +import io.anuke.mindustry.world.modules.InventoryModule; import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Graphics; import io.anuke.ucore.core.Timers; @@ -35,40 +35,58 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -public class UnitFactory extends Block { +public class UnitFactory extends Block{ protected UnitType type; - protected ItemStack[] requirements; protected float produceTime = 1000f; - protected float powerUse = 0.1f; protected float openDuration = 50f; protected float launchVelocity = 0f; protected String unitRegion; - public UnitFactory(String name) { + public UnitFactory(String name){ super(name); update = true; hasPower = true; hasItems = true; solidifes = true; + + consumes.require(ConsumeItems.class); + } + + @Remote(called = Loc.server, in = In.blocks) + public static void onUnitFactorySpawn(Tile tile){ + UnitFactoryEntity entity = tile.entity(); + UnitFactory factory = (UnitFactory) tile.block(); + + entity.buildTime = 0f; + entity.hasSpawned = true; + + Effects.shake(2f, 3f, entity); + Effects.effect(BlockFx.producesmoke, tile.drawx(), tile.drawy()); + + if(!Net.client()){ + BaseUnit unit = factory.type.create(tile.getTeam()); + unit.setSpawner(tile); + unit.set(tile.drawx(), tile.drawy()); + unit.add(); + unit.getVelocity().y = factory.launchVelocity; + } } @Override - public void setStats() { + public void setStats(){ super.setStats(); - stats.add(BlockStat.inputItems, new ItemListValue(requirements)); - stats.add(BlockStat.powerUse, powerUse * 60f, StatUnit.powerSecond); - stats.add(BlockStat.craftSpeed, produceTime/60f, StatUnit.seconds); + stats.add(BlockStat.craftSpeed, produceTime / 60f, StatUnit.seconds); } @Override - public boolean isSolidFor(Tile tile) { + public boolean isSolidFor(Tile tile){ UnitFactoryEntity entity = tile.entity(); return type.isFlying || !entity.open; } @Override - public void setBars() { + public void setBars(){ super.setBars(); bars.add(new BlockBar(BarType.production, true, tile -> tile.entity().buildTime / produceTime)); @@ -76,22 +94,22 @@ public class UnitFactory extends Block { } @Override - public TextureRegion[] getIcon() { + public TextureRegion[] getIcon(){ return new TextureRegion[]{ - Draw.region(name), - Draw.region(name + "-top") + Draw.region(name), + Draw.region(name + "-top") }; } @Override - public void draw(Tile tile) { + public void draw(Tile tile){ UnitFactoryEntity entity = tile.entity(); TextureRegion region = Draw.region(unitRegion == null ? type.name : unitRegion); Draw.rect(name(), tile.drawx(), tile.drawy()); Shaders.build.region = region; - Shaders.build.progress = entity.buildTime/produceTime; + Shaders.build.progress = entity.buildTime / produceTime; Shaders.build.color.set(Palette.accent); Shaders.build.color.a = entity.speedScl; Shaders.build.time = -entity.time / 10f; @@ -105,7 +123,7 @@ public class UnitFactory extends Block { Draw.alpha(entity.speedScl); Lines.lineAngleCenter( - tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize/2f*size - 2f), + tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 2f * size - 2f), tile.drawy(), 90, size * Vars.tilesize - 4f); @@ -116,18 +134,16 @@ public class UnitFactory extends Block { } @Override - public void update(Tile tile) { + public void update(Tile tile){ UnitFactoryEntity entity = tile.entity(); - float used = Math.min(powerUse * Timers.delta(), powerCapacity); - entity.time += Timers.delta() * entity.speedScl; if(entity.openCountdown > 0){ if(entity.openCountdown > Timers.delta()){ entity.openCountdown -= Timers.delta(); }else{ - if(type.isFlying || !Units.anyEntities(tile)) { + if(type.isFlying || !Units.anyEntities(tile)){ entity.open = false; entity.openCountdown = -1; }else{ @@ -136,11 +152,21 @@ public class UnitFactory extends Block { } } - if(!entity.hasSpawned && hasRequirements(entity.items, entity.buildTime/produceTime) && - entity.power.amount >= used && !entity.open){ + /* + if(!entity.hasSpawned){ + for(BaseUnit unit : unitGroups[tile.getTeamID()].all()){ + if(unit.getType() == type && unit.getSpawner() == null){ + entity.hasSpawned = true; + unit.setSpawner(tile); + break; + } + } + }*/ + + if(!entity.hasSpawned && hasRequirements(entity.items, entity.buildTime / produceTime) && + entity.cons.valid() && !entity.open){ entity.buildTime += Timers.delta(); - entity.power.amount -= used; entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.05f); }else{ if(!entity.open) entity.speedScl = Mathf.lerpDelta(entity.speedScl, 0f, 0.05f); @@ -153,16 +179,16 @@ public class UnitFactory extends Block { entity.openCountdown = openDuration; - for(ItemStack stack : requirements){ - entity.items.removeItem(stack.item, stack.amount); + for(ItemStack stack : consumes.items()){ + entity.items.remove(stack.item, stack.amount); } } } @Override - public boolean acceptItem(Item item, Tile tile, Tile source) { - for(ItemStack stack : requirements){ - if(item == stack.item && tile.entity.items.getItem(item) <= stack.amount*2){ + public boolean acceptItem(Item item, Tile tile, Tile source){ + for(ItemStack stack : consumes.items()){ + if(item == stack.item && tile.entity.items.get(item) <= stack.amount * 2){ return true; } } @@ -170,39 +196,19 @@ public class UnitFactory extends Block { } @Override - public TileEntity getEntity() { + public TileEntity getEntity(){ return new UnitFactoryEntity(); } protected boolean hasRequirements(InventoryModule inv, float fraction){ - for(ItemStack stack : requirements){ - if(!inv.hasItem(stack.item, (int)(fraction * stack.amount))){ + for(ItemStack stack : consumes.items()){ + if(!inv.has(stack.item, (int) (fraction * stack.amount))){ return false; } } return true; } - @Remote(called = Loc.server, in = In.blocks) - public static void onUnitFactorySpawn(Tile tile){ - UnitFactoryEntity entity = tile.entity(); - UnitFactory factory = (UnitFactory)tile.block(); - - entity.buildTime = 0f; - entity.hasSpawned = true; - - Effects.shake(2f, 3f, entity); - Effects.effect(BlockFx.producesmoke, tile.drawx(), tile.drawy()); - - if(!Net.client()) { - BaseUnit unit = factory.type.create(tile.getTeam()); - unit.setSpawner(tile); - unit.set(tile.drawx(), tile.drawy()); - unit.add(); - unit.getVelocity().y = factory.launchVelocity; - } - } - public static class UnitFactoryEntity extends TileEntity{ public float buildTime; public boolean open; @@ -212,13 +218,15 @@ public class UnitFactory extends Block { public boolean hasSpawned; @Override - public void write(DataOutputStream stream) throws IOException { + public void write(DataOutputStream stream) throws IOException{ stream.writeFloat(buildTime); + stream.writeBoolean(hasSpawned); } @Override - public void read(DataInputStream stream) throws IOException { + public void read(DataInputStream stream) throws IOException{ buildTime = stream.readFloat(); + hasSpawned = stream.readBoolean(); } } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/UnloadPoint.java b/core/src/io/anuke/mindustry/world/blocks/units/UnloadPoint.java index 6d2ef8d2d6..b7dfd4ae7e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/UnloadPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/UnloadPoint.java @@ -1,4 +1,4 @@ package io.anuke.mindustry.world.blocks.units; -public class UnloadPoint { +public class UnloadPoint{ } diff --git a/core/src/io/anuke/mindustry/world/consumers/Consume.java b/core/src/io/anuke/mindustry/world/consumers/Consume.java new file mode 100644 index 0000000000..8408389933 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/Consume.java @@ -0,0 +1,58 @@ +package io.anuke.mindustry.world.consumers; + +import com.badlogic.gdx.graphics.Color; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.graphics.Palette; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.ucore.scene.ui.Tooltip; +import io.anuke.ucore.scene.ui.layout.Table; + +import static io.anuke.mindustry.Vars.mobile; + +public abstract class Consume{ + private boolean optional; + private boolean update = true; + + public Consume optional(boolean optional){ + this.optional = optional; + return this; + } + + public Consume update(boolean update){ + this.update = update; + return this; + } + + public boolean isOptional(){ + return optional; + } + + public boolean isUpdate(){ + return update; + } + + public void build(Table table){ + Table t = new Table("clear"); + t.margin(4); + buildTooltip(t); + + int scale = mobile ? 4 : 3; + + table.table(out -> { + out.addImage(getIcon()).size(10 * scale).color(Color.DARK_GRAY).padRight(-10 * scale).padBottom(-scale * 2); + out.addImage(getIcon()).size(10 * scale).color(Palette.accent); + out.addImage("icon-missing").size(10 * scale).color(Palette.remove).padLeft(-10 * scale); + }).size(10 * scale).get().addListener(new Tooltip<>(t)); + } + + public abstract void buildTooltip(Table table); + + public abstract String getIcon(); + + public abstract void update(Block block, TileEntity entity); + + public abstract boolean valid(Block block, TileEntity entity); + + public abstract void display(BlockStats stats); +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumeItem.java b/core/src/io/anuke/mindustry/world/consumers/ConsumeItem.java new file mode 100644 index 0000000000..61be341aa9 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumeItem.java @@ -0,0 +1,58 @@ +package io.anuke.mindustry.world.consumers; + +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.type.ItemStack; +import io.anuke.mindustry.ui.ItemImage; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumeItem extends Consume{ + private final Item item; + private final int amount; + + public ConsumeItem(Item item){ + this.item = item; + this.amount = 1; + } + + public ConsumeItem(Item item, int amount){ + this.item = item; + this.amount = amount; + } + + public int getAmount(){ + return amount; + } + + public Item get(){ + return item; + } + + @Override + public void buildTooltip(Table table){ + table.add(new ItemImage(new ItemStack(item, amount))).size(8 * 4); + } + + @Override + public String getIcon(){ + return "icon-item"; + } + + @Override + public void update(Block block, TileEntity entity){ + //doesn't update because consuming items is very specific + } + + @Override + public boolean valid(Block block, TileEntity entity){ + return entity.items.has(item, amount); + } + + @Override + public void display(BlockStats stats){ + stats.add(BlockStat.inputItem, item); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/io/anuke/mindustry/world/consumers/ConsumeItemFilter.java new file mode 100644 index 0000000000..6860fee801 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumeItemFilter.java @@ -0,0 +1,62 @@ +package io.anuke.mindustry.world.consumers; + +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.mindustry.world.meta.values.ItemFilterValue; +import io.anuke.ucore.function.Predicate; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumeItemFilter extends Consume{ + private final Predicate filter; + + public ConsumeItemFilter(Predicate item){ + this.filter = item; + } + + @Override + public void buildTooltip(Table table){ + Array list = new Array<>(); + + for(Item item : Item.all()){ + if(filter.test(item)) list.add(item); + } + + for(int i = 0; i < list.size; i++){ + Item item = list.get(i); + table.addImage(item.region).size(8 * 4).padRight(2).padLeft(2); + if(i != list.size - 1){ + table.add("/"); + } + } + } + + @Override + public String getIcon(){ + return "icon-item"; + } + + @Override + public void update(Block block, TileEntity entity){ + + } + + @Override + public boolean valid(Block block, TileEntity entity){ + for(int i = 0; i < Item.all().size; i++){ + Item item = Item.getByID(i); + if(entity.items.has(item) && this.filter.test(item)){ + return true; + } + } + return false; + } + + @Override + public void display(BlockStats stats){ + stats.add(BlockStat.inputItems, new ItemFilterValue(filter)); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumeItems.java b/core/src/io/anuke/mindustry/world/consumers/ConsumeItems.java new file mode 100644 index 0000000000..4215ac2fc2 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumeItems.java @@ -0,0 +1,49 @@ +package io.anuke.mindustry.world.consumers; + +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.type.ItemStack; +import io.anuke.mindustry.ui.ItemImage; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.mindustry.world.meta.values.ItemListValue; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumeItems extends Consume{ + private ItemStack[] items; + + public ConsumeItems(ItemStack[] items){ + this.items = items; + } + + public ItemStack[] getItems(){ + return items; + } + + @Override + public void buildTooltip(Table table){ + for(ItemStack stack : items){ + table.add(new ItemImage(stack)).size(8 * 4).padRight(5); + } + } + + @Override + public String getIcon(){ + return "icon-item"; + } + + @Override + public void update(Block block, TileEntity entity){ + + } + + @Override + public boolean valid(Block block, TileEntity entity){ + return entity.items.has(items); + } + + @Override + public void display(BlockStats stats){ + stats.add(BlockStat.inputItems, new ItemListValue(items)); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquid.java b/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquid.java new file mode 100644 index 0000000000..f8962ae760 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquid.java @@ -0,0 +1,58 @@ +package io.anuke.mindustry.world.consumers; + +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumeLiquid extends Consume{ + protected final float use; + protected final Liquid liquid; + + public ConsumeLiquid(Liquid liquid, float use){ + this.liquid = liquid; + this.use = use; + } + + public float used(){ + return use; + } + + public Liquid get(){ + return liquid; + } + + @Override + public void buildTooltip(Table table){ + table.addImage(liquid.getContentIcon()).size(8 * 3); + } + + @Override + public String getIcon(){ + return "icon-liquid"; + } + + @Override + public void update(Block block, TileEntity entity){ + entity.liquids.remove(liquid, Math.min(use(block), entity.liquids.get(liquid))); + } + + @Override + public boolean valid(Block block, TileEntity entity){ + return entity.liquids.get(liquid) >= use(block); + } + + @Override + public void display(BlockStats stats){ + stats.add(BlockStat.liquidUse, use * 60f, StatUnit.liquidSecond); + stats.add(BlockStat.inputLiquid, liquid); + } + + float use(Block block){ + return Math.min(use * Timers.delta(), block.liquidCapacity); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquidFilter.java b/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquidFilter.java new file mode 100644 index 0000000000..abbd36df25 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumeLiquidFilter.java @@ -0,0 +1,76 @@ +package io.anuke.mindustry.world.consumers; + +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.mindustry.world.meta.values.LiquidFilterValue; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.function.Predicate; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumeLiquidFilter extends Consume{ + private final Predicate filter; + private final float use; + private final boolean isFuel; + + public ConsumeLiquidFilter(Predicate liquid, float amount, boolean isFuel){ + this.filter = liquid; + this.use = amount; + this.isFuel = isFuel; + } + + public ConsumeLiquidFilter(Predicate liquid, float amount){ + this(liquid, amount, false); + } + + @Override + public void buildTooltip(Table table){ + Array list = new Array<>(); + + for(Liquid item : Liquid.all()){ + if(!item.isHidden() && filter.test(item)) list.add(item); + } + + for(int i = 0; i < list.size; i++){ + Liquid item = list.get(i); + table.addImage(item.getContentIcon()).size(8 * 3).padRight(2).padLeft(2).padTop(2).padBottom(2); + if(i != list.size - 1){ + table.add("/"); + } + } + } + + @Override + public String getIcon(){ + return "icon-liquid"; + } + + @Override + public void update(Block block, TileEntity entity){ + entity.liquids.remove(entity.liquids.current(), use(block)); + } + + @Override + public boolean valid(Block block, TileEntity entity){ + return filter.test(entity.liquids.current()) && entity.liquids.currentAmount() >= use(block); + } + + @Override + public void display(BlockStats stats){ + if(isFuel){ + stats.add(BlockStat.inputLiquidFuel, new LiquidFilterValue(filter)); + stats.add(BlockStat.liquidFuelUse, 60f * use, StatUnit.liquidSecond); + }else{ + stats.add(BlockStat.inputLiquid, new LiquidFilterValue(filter)); + stats.add(BlockStat.liquidUse, 60f * use, StatUnit.liquidSecond); + } + } + + float use(Block block){ + return Math.min(use * Timers.delta(), block.liquidCapacity); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/ConsumePower.java b/core/src/io/anuke/mindustry/world/consumers/ConsumePower.java new file mode 100644 index 0000000000..82bd1e56e0 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/ConsumePower.java @@ -0,0 +1,46 @@ +package io.anuke.mindustry.world.consumers; + +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.meta.BlockStat; +import io.anuke.mindustry.world.meta.BlockStats; +import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.scene.ui.layout.Table; + +public class ConsumePower extends Consume{ + private final float use; + + public ConsumePower(float use){ + this.use = use; + } + + @Override + public void buildTooltip(Table table){ + + } + + @Override + public String getIcon(){ + return "icon-power"; + } + + @Override + public void update(Block block, TileEntity entity){ + entity.power.amount -= Math.min(use(block), entity.power.amount); + } + + @Override + public boolean valid(Block block, TileEntity entity){ + return entity.power.amount >= use(block); + } + + @Override + public void display(BlockStats stats){ + stats.add(BlockStat.powerUse, use * 60f, StatUnit.powerSecond); + } + + float use(Block block){ + return Math.min(use * Timers.delta(), block.powerCapacity); + } +} diff --git a/core/src/io/anuke/mindustry/world/consumers/Consumers.java b/core/src/io/anuke/mindustry/world/consumers/Consumers.java new file mode 100644 index 0000000000..a0ea86d201 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/consumers/Consumers.java @@ -0,0 +1,115 @@ +package io.anuke.mindustry.world.consumers; + +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.ObjectSet; +import com.badlogic.gdx.utils.reflect.ClassReflection; +import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.type.ItemStack; +import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.Block; +import io.anuke.ucore.function.Consumer; +import io.anuke.ucore.util.ThreadArray; + +public class Consumers{ + private ObjectMap, Consume> map = new ObjectMap<>(); + private ObjectSet> required = new ObjectSet<>(); + private ThreadArray results = new ThreadArray<>(); + + public void require(Class type){ + required.add(type); + } + + public void checkRequired(Block block){ + for(Class c : required){ + if(!map.containsKey(c)){ + throw new RuntimeException("Missing required consumer of type \"" + ClassReflection.getSimpleName(c) + "\" in block \"" + block.name + "\"!"); + } + } + + for(Consume cons : map.values()){ + results.add(cons); + } + } + + public ConsumePower power(float amount){ + ConsumePower p = new ConsumePower(amount); + add(p); + return p; + } + + public ConsumeLiquid liquid(Liquid liquid, float amount){ + ConsumeLiquid c = new ConsumeLiquid(liquid, amount); + add(c); + return c; + } + + public ConsumeItem item(Item item){ + return item(item, 1); + } + + public ConsumeItem item(Item item, int amount){ + ConsumeItem i = new ConsumeItem(item, amount); + add(i); + return i; + } + + public ConsumeItems items(ItemStack[] items){ + ConsumeItems i = new ConsumeItems(items); + add(i); + return i; + } + + public Item item(){ + return get(ConsumeItem.class).get(); + } + + public ItemStack[] items(){ + return get(ConsumeItems.class).getItems(); + } + + public int itemAmount(){ + return get(ConsumeItem.class).getAmount(); + } + + public Liquid liquid(){ + return get(ConsumeLiquid.class).get(); + } + + public Consume add(Consume consume){ + map.put(consume.getClass(), consume); + return consume; + } + + public void remove(Class type){ + map.remove(type); + } + + public boolean has(Class type){ + return map.containsKey(type); + } + + public T get(Class type){ + if(!map.containsKey(type)){ + throw new IllegalArgumentException("Block does not contain consumer of type '" + type + "'!"); + } + return (T) map.get(type); + } + + public Iterable all(){ + return map.values(); + } + + public ThreadArray array(){ + return results; + } + + public boolean hasAny(){ + return map.size > 0; + } + + public void forEach(Consumer cons){ + for(Consume c : all()){ + cons.accept(c); + } + } +} diff --git a/core/src/io/anuke/mindustry/world/mapgen/GenProperties.java b/core/src/io/anuke/mindustry/world/mapgen/GenProperties.java index 88a00e6709..b11aca6b8c 100644 --- a/core/src/io/anuke/mindustry/world/mapgen/GenProperties.java +++ b/core/src/io/anuke/mindustry/world/mapgen/GenProperties.java @@ -1,6 +1,6 @@ package io.anuke.mindustry.world.mapgen; -public class GenProperties { +public class GenProperties{ public long seed; public MapStyle maps; public OreStyle ores; @@ -11,24 +11,40 @@ public class GenProperties { public EnvironmentStyle environment; enum MapStyle{ - /**256x512*/ + /** + * 256x512 + */ longY, - /**128x256*/ + /** + * 128x256 + */ smallY, - /**128x128*/ + /** + * 128x128 + */ small, - /**256x256*/ + /** + * 256x256 + */ normal } enum OreStyle{ - /**'vanilla' noise-distributed ores*/ + /** + * 'vanilla' noise-distributed ores + */ normal, - /**ores hug the walls*/ + /** + * ores hug the walls + */ nearWalls, - /**ores hug all liquid rivers*/ + /** + * ores hug all liquid rivers + */ nearRivers, - /**large veins*/ + /** + * large veins + */ largeVeins } @@ -40,22 +56,36 @@ public class GenProperties { } enum RiverStyle{ - /**long thin river spanning entire map*/ + /** + * long thin river spanning entire map + */ longThin, - /**long river branching into many others*/ + /** + * long river branching into many others + */ longBranch, - /**one long, thick river*/ + /** + * one long, thick river + */ longThick, - /**short, thick river that ends in a lake*/ + /** + * short, thick river that ends in a lake + */ shortLake } enum TerrainStyle{ - /**bordered around by the normal material*/ + /** + * bordered around by the normal material + */ normal, - /**everything is islands*/ + /** + * everything is islands + */ waterIslands, - /**everything is islands: lava edition*/ + /** + * everything is islands: lava edition + */ lavaIslands } diff --git a/core/src/io/anuke/mindustry/world/mapgen/WorldGenerator.java b/core/src/io/anuke/mindustry/world/mapgen/WorldGenerator.java index 27b3044e7b..6db249a9f1 100644 --- a/core/src/io/anuke/mindustry/world/mapgen/WorldGenerator.java +++ b/core/src/io/anuke/mindustry/world/mapgen/WorldGenerator.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.world.mapgen; import com.badlogic.gdx.math.GridPoint2; +import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.IntArray; @@ -26,233 +27,236 @@ import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.world; -public class WorldGenerator { - static int oreIndex = 0; - - /**Should fill spawns with the correct spawnpoints.*/ - public static void loadTileData(Tile[][] tiles, MapTileData data, boolean genOres, int seed){ - data.position(0, 0); - TileDataMarker marker = data.newDataMarker(); +public class WorldGenerator{ + static int oreIndex = 0; - for(int y = 0; y < data.height(); y ++){ - for(int x = 0; x < data.width(); x ++){ - data.read(marker); - - tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.blockpart.id ? 0 : marker.wall, marker.rotation, marker.team, marker.elevation); - } - } + /** + * Should fill spawns with the correct spawnpoints. + */ + public static void loadTileData(Tile[][] tiles, MapTileData data, boolean genOres, int seed){ + data.position(0, 0); + TileDataMarker marker = data.newDataMarker(); - prepareTiles(tiles, seed, genOres); - } + for(int y = 0; y < data.height(); y++){ + for(int x = 0; x < data.width(); x++){ + data.read(marker); - public static void prepareTiles(Tile[][] tiles, int seed, boolean genOres){ - - //find multiblocks - IntArray multiblocks = new IntArray(); + tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.blockpart.id ? 0 : marker.wall, marker.rotation, marker.team, marker.elevation); + } + } - for(int x = 0; x < tiles.length; x ++) { - for (int y = 0; y < tiles[0].length; y++) { - Tile tile = tiles[x][y]; - - Team team = tile.getTeam(); + prepareTiles(tiles, seed, genOres); + } - if(tile.block() == StorageBlocks.core && - state.teams.has(team)){ - state.teams.get(team).cores.add(tile); - } - - if(tiles[x][y].block().isMultiblock()){ - multiblocks.add(tiles[x][y].packedPosition()); - } - } - } + public static void prepareTiles(Tile[][] tiles, int seed, boolean genOres){ - //place multiblocks now - for(int i = 0; i < multiblocks.size; i ++){ - int pos = multiblocks.get(i); + //find multiblocks + IntArray multiblocks = new IntArray(); - int x = pos % tiles.length; - int y = pos / tiles[0].length; + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ + Tile tile = tiles[x][y]; - Block result = tiles[x][y].block(); - Team team = tiles[x][y].getTeam(); + Team team = tile.getTeam(); - int offsetx = -(result.size-1)/2; - int offsety = -(result.size-1)/2; + if(tile.block() == StorageBlocks.core && + state.teams.has(team)){ + state.teams.get(team).cores.add(tile); + } - for(int dx = 0; dx < result.size; dx ++){ - for(int dy = 0; dy < result.size; dy ++){ - int worldx = dx + offsetx + x; - int worldy = dy + offsety + y; - if(!(worldx == x && worldy == y)){ - Tile toplace = world.tile(worldx, worldy); - if(toplace != null) { - toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety)); - toplace.setTeam(team); - } - } - } - } - } + if(tiles[x][y].block().isMultiblock()){ + multiblocks.add(tiles[x][y].packedPosition()); + } + } + } - //update cliffs, occlusion data - for(int x = 0; x < tiles.length; x ++){ - for(int y = 0; y < tiles[0].length; y ++) { - Tile tile = tiles[x][y]; + //place multiblocks now + for(int i = 0; i < multiblocks.size; i++){ + int pos = multiblocks.get(i); - tile.updateOcclusion(); + int x = pos % tiles.length; + int y = pos / tiles[0].length; - //fix things on cliffs that shouldn't be - if(tile.block() != Blocks.air && tile.cliffs != 0){ - tile.setBlock(Blocks.air); - } - } - } + Block result = tiles[x][y].block(); + Team team = tiles[x][y].getTeam(); - oreIndex = 0; + int offsetx = -(result.size - 1) / 2; + int offsety = -(result.size - 1) / 2; - if(genOres) { - Array ores = Array.with( - new OreEntry(Items.tungsten, 0.3f, seed), - new OreEntry(Items.coal, 0.284f, seed), - new OreEntry(Items.lead, 0.28f, seed), - new OreEntry(Items.titanium, 0.27f, seed), - new OreEntry(Items.thorium, 0.26f, seed) - ); + for(int dx = 0; dx < result.size; dx++){ + for(int dy = 0; dy < result.size; dy++){ + int worldx = dx + offsetx + x; + int worldy = dy + offsety + y; + if(!(worldx == x && worldy == y)){ + Tile toplace = world.tile(worldx, worldy); + if(toplace != null){ + toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety)); + toplace.setTeam(team); + } + } + } + } + } - for (int x = 0; x < tiles.length; x++) { - for (int y = 0; y < tiles[0].length; y++) { + //update cliffs, occlusion data + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ + Tile tile = tiles[x][y]; - Tile tile = tiles[x][y]; + tile.updateOcclusion(); - if(!tile.floor().hasOres || tile.cliffs != 0 || tile.block() != Blocks.air){ - continue; - } + //fix things on cliffs that shouldn't be + if(tile.block() != Blocks.air && tile.cliffs != 0){ + tile.setBlock(Blocks.air); + } + } + } - for(int i = ores.size-1; i >= 0; i --){ - OreEntry entry = ores.get(i); - if(entry.noise.octaveNoise2D(2, 0.7, 1f / (2 + i*2), x, y)/2f + - entry.ridge.getValue(x, y, 1f / (28 + i*4)) >= 2.0f - entry.frequency*4.0f - && entry.ridge.getValue(x+9999, y+9999, 1f/100f) > 0.4){ - tile.setFloor((Floor) OreBlocks.get(tile.floor(), entry.item)); - break; - } - } - } - } - } - } + oreIndex = 0; - public static void generateMap(Tile[][] tiles, int seed){ - Simplex sim = new Simplex(Mathf.random(99999)); - Simplex sim2 = new Simplex(Mathf.random(99999)); - Simplex sim3 = new Simplex(Mathf.random(99999)); + if(genOres){ + Array ores = Array.with( + new OreEntry(Items.tungsten, 0.3f, seed), + new OreEntry(Items.coal, 0.284f, seed), + new OreEntry(Items.lead, 0.28f, seed), + new OreEntry(Items.titanium, 0.27f, seed), + new OreEntry(Items.thorium, 0.26f, seed) + ); - SeedRandom random = new SeedRandom(Mathf.random(99999)); + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ - int width = tiles.length, height = tiles[0].length; + Tile tile = tiles[x][y]; - ObjectMap decoration = new ObjectMap<>(); + if(!tile.floor().hasOres || tile.cliffs != 0 || tile.block() != Blocks.air){ + continue; + } - decoration.put(Blocks.grass, Blocks.shrub); - decoration.put(Blocks.stone, Blocks.rock); - decoration.put(Blocks.ice, Blocks.icerock); - decoration.put(Blocks.snow, Blocks.icerock); - decoration.put(Blocks.blackstone, Blocks.blackrock); + for(int i = ores.size - 1; i >= 0; i--){ + OreEntry entry = ores.get(i); + if(entry.noise.octaveNoise2D(1, 0.7, 1f / (4 + i * 2), x, y) / 4f + + Math.abs(0.5f - entry.noise.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), x, y)) > 0.48f && + Math.abs(0.5f - entry.noise.octaveNoise2D(1, 1, 1f / (55 + i * 4), x, y)) > 0.22f){ + tile.setFloor((Floor) OreBlocks.get(tile.floor(), entry.item)); + break; + } + } + } + } + } + } - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - Block floor = Blocks.stone; - Block wall = Blocks.air; + public static void generateMap(Tile[][] tiles, int seed){ + MathUtils.random.setSeed((long) (Math.random() * 99999999)); + Simplex sim = new Simplex(Mathf.random(99999)); + Simplex sim2 = new Simplex(Mathf.random(99999)); + Simplex sim3 = new Simplex(Mathf.random(99999)); - double elevation = sim.octaveNoise2D(3, 0.5, 1f/100, x, y) * 4.1 - 1; - double temp = sim3.octaveNoise2D(7, 0.53, 1f/320f, x, y); + SeedRandom random = new SeedRandom(Mathf.random(99999)); - double r = sim2.octaveNoise2D(1, 0.6, 1f/70, x, y); - double edgeDist = Math.max(width/2, height/2) - Math.max(Math.abs(x - width/2), Math.abs(y - height/2)); - double dst = Vector2.dst(width/2, height/2, x, y); - double elevDip = 30; + int width = tiles.length, height = tiles[0].length; - double border = 14; + ObjectMap decoration = new ObjectMap<>(); - if(edgeDist < border){ - elevation += (border - edgeDist)/6.0; - } + decoration.put(Blocks.grass, Blocks.shrub); + decoration.put(Blocks.stone, Blocks.rock); + decoration.put(Blocks.ice, Blocks.icerock); + decoration.put(Blocks.snow, Blocks.icerock); + decoration.put(Blocks.blackstone, Blocks.blackrock); - if(temp < 0.35){ - floor = Blocks.snow; - }else if(temp < 0.45){ - floor = Blocks.stone; - }else if(temp < 0.65){ - floor = Blocks.grass; - }else if(temp < 0.8){ - floor = Blocks.sand; - }else if(temp < 0.9){ - floor = Blocks.blackstone; - elevation = 0f; - }else{ - floor = Blocks.lava; - } + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + Block floor = Blocks.stone; + Block wall = Blocks.air; - if(dst < elevDip){ - elevation -= (elevDip - dst)/elevDip * 3.0; - }else if(r > 0.9){ - floor = Blocks.water; - elevation = 0; + double elevation = sim.octaveNoise2D(3, 0.5, 1f / 100, x, y) * 4.1 - 1; + double temp = sim3.octaveNoise2D(7, 0.54, 1f / 320f, x, y); - if(r > 0.94){ - floor = Blocks.deepwater; - } - } + double r = sim2.octaveNoise2D(1, 0.6, 1f / 70, x, y); + double edgeDist = Math.max(width / 2, height / 2) - Math.max(Math.abs(x - width / 2), Math.abs(y - height / 2)); + double dst = Vector2.dst(width / 2, height / 2, x, y); + double elevDip = 30; - if(wall == Blocks.air && decoration.containsKey(floor) && random.chance(0.03)){ - wall = decoration.get(floor); - } + double border = 14; - Tile tile = new Tile(x, y, (byte)floor.id, (byte)wall.id); - tile.elevation = (byte)Math.max(elevation, 0); - tiles[x][y] = tile; - } - } + if(edgeDist < border){ + elevation += (border - edgeDist) / 6.0; + } - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - Tile tile = tiles[x][y]; + if(temp < 0.35){ + floor = Blocks.snow; + }else if(temp < 0.45){ + floor = Blocks.stone; + }else if(temp < 0.65){ + floor = Blocks.grass; + }else if(temp < 0.8){ + floor = Blocks.sand; + }else if(temp < 0.9){ + floor = Blocks.blackstone; + elevation = 0f; + }else{ + floor = Blocks.lava; + } - byte elevation = tile.elevation; + if(dst < elevDip){ + elevation -= (elevDip - dst) / elevDip * 3.0; + }else if(r > 0.9){ + floor = Blocks.water; + elevation = 0; - for(GridPoint2 point : Geometry.d4){ - if(!Mathf.inBounds(x + point.x, y + point.y, width, height)) continue; - if(tiles[x + point.x][y + point.y].elevation < elevation){ + if(r > 0.94){ + floor = Blocks.deepwater; + } + } - if(Mathf.chance(0.05)){ - tile.elevation = -1; - } - break; - } - } - } - } + if(wall == Blocks.air && decoration.containsKey(floor) && random.chance(0.03)){ + wall = decoration.get(floor); + } - tiles[width/2][height/2].setBlock(StorageBlocks.core); - tiles[width/2][height/2].setTeam(Team.blue); - - prepareTiles(tiles, seed, true); - } + Tile tile = new Tile(x, y, (byte) floor.id, (byte) wall.id); + tile.elevation = (byte) Math.max(elevation, 0); + tiles[x][y] = tile; + } + } - static class OreEntry{ - final float frequency; - final Item item; - final Simplex noise; - final RidgedPerlin ridge; - final int index; + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + Tile tile = tiles[x][y]; - OreEntry(Item item, float frequency, int seed) { - this.frequency = frequency; - this.item = item; - this.noise = new Simplex(seed + oreIndex); - this.ridge = new RidgedPerlin(seed + oreIndex, 2); - this.index = oreIndex ++; - } - } + byte elevation = tile.elevation; + + for(GridPoint2 point : Geometry.d4){ + if(!Mathf.inBounds(x + point.x, y + point.y, width, height)) continue; + if(tiles[x + point.x][y + point.y].elevation < elevation){ + + if(Mathf.chance(0.05)){ + tile.elevation = -1; + } + break; + } + } + } + } + + tiles[width / 2][height / 2].setBlock(StorageBlocks.core); + tiles[width / 2][height / 2].setTeam(Team.blue); + + prepareTiles(tiles, seed, true); + } + + public static class OreEntry{ + final float frequency; + final Item item; + final Simplex noise; + final RidgedPerlin ridge; + final int index; + + OreEntry(Item item, float frequency, int seed){ + this.frequency = frequency; + this.item = item; + this.noise = new Simplex(seed + oreIndex); + this.ridge = new RidgedPerlin(seed + oreIndex, 2); + this.index = oreIndex++; + } + } } diff --git a/core/src/io/anuke/mindustry/world/meta/BlockBar.java b/core/src/io/anuke/mindustry/world/meta/BlockBar.java index d322dffa5f..d692e152b5 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockBar.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockBar.java @@ -3,12 +3,12 @@ package io.anuke.mindustry.world.meta; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Tile; -public class BlockBar { +public class BlockBar{ public final ValueSupplier value; public final BarType type; public final boolean top; - public BlockBar(BarType type, boolean top, ValueSupplier value) { + public BlockBar(BarType type, boolean top, ValueSupplier value){ this.value = value; this.type = type; this.top = top; diff --git a/core/src/io/anuke/mindustry/world/meta/BlockBars.java b/core/src/io/anuke/mindustry/world/meta/BlockBars.java index 6b02067976..35507b616b 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockBars.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockBars.java @@ -3,8 +3,8 @@ package io.anuke.mindustry.world.meta; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.world.BarType; -public class BlockBars { - private Array list = Array.with(new BlockBar(BarType.health, false, tile -> tile.entity.health / (float)tile.block().health)); +public class BlockBars{ + private Array list = Array.with(new BlockBar(BarType.health, false, tile -> tile.entity.health / (float) tile.block().health)); public void add(BlockBar bar){ list.add(bar); @@ -36,7 +36,7 @@ public class BlockBars { list.removeAll(removals, true); } - public Array list() { + public Array list(){ return list; } } diff --git a/core/src/io/anuke/mindustry/world/meta/BlockFlag.java b/core/src/io/anuke/mindustry/world/meta/BlockFlag.java index 9fb0025c0c..44820e6646 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockFlag.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockFlag.java @@ -1,17 +1,29 @@ package io.anuke.mindustry.world.meta; -public enum BlockFlag { - /**General important target for all types of units.*/ +public enum BlockFlag{ + /** + * General important target for all types of units. + */ target(0), - /**Point to resupply resources.*/ + /** + * Point to resupply resources. + */ resupplyPoint(Float.MAX_VALUE), - /**Point to drop off resources.*/ + /** + * Point to drop off resources. + */ dropPoint(Float.MAX_VALUE), - /**Producer of important goods.*/ + /** + * Producer of important goods. + */ producer(20), - /**Producer or storage unit of volatile materials.*/ + /** + * Producer or storage unit of volatile materials. + */ explosive(10), - /**Repair point.*/ + /** + * Repair point. + */ repair(Float.MAX_VALUE); public final float cost; diff --git a/core/src/io/anuke/mindustry/world/meta/BlockGroup.java b/core/src/io/anuke/mindustry/world/meta/BlockGroup.java index e9795a956a..dd90943ea0 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockGroup.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockGroup.java @@ -1,5 +1,5 @@ package io.anuke.mindustry.world.meta; -public enum BlockGroup { +public enum BlockGroup{ none, walls, turrets, transportation, power, liquids, drills } diff --git a/core/src/io/anuke/mindustry/world/meta/BlockStat.java b/core/src/io/anuke/mindustry/world/meta/BlockStat.java index 4279f272c9..97f17c6c25 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockStat.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockStat.java @@ -2,8 +2,10 @@ package io.anuke.mindustry.world.meta; import io.anuke.ucore.util.Bundles; -/**Describes one type of stat for a block.*/ -public enum BlockStat { +/** + * Describes one type of stat for a block. + */ +public enum BlockStat{ health(StatCategory.general), size(StatCategory.general), @@ -14,15 +16,18 @@ public enum BlockStat { liquidCapacity(StatCategory.liquids), liquidOutput(StatCategory.liquids), + coolant(StatCategory.liquids), + coolantUse(StatCategory.liquids), powerCapacity(StatCategory.power), powerUse(StatCategory.power), powerRange(StatCategory.power), powerTransferSpeed(StatCategory.power), maxPowerGeneration(StatCategory.power), + inputLiquidFuel(StatCategory.power), + liquidFuelUse(StatCategory.power), inputLiquid(StatCategory.crafting), - inputLiquidAux(StatCategory.crafting), liquidUse(StatCategory.crafting), inputItem(StatCategory.crafting), inputItems(StatCategory.crafting), @@ -38,14 +43,12 @@ public enum BlockStat { shots(StatCategory.shooting), reload(StatCategory.shooting), powerShot(StatCategory.shooting), - targetsAir(StatCategory.shooting) -, - ; + targetsAir(StatCategory.shooting),; public final StatCategory category; - BlockStat(StatCategory category) { + BlockStat(StatCategory category){ this.category = category; } diff --git a/core/src/io/anuke/mindustry/world/meta/BlockStats.java b/core/src/io/anuke/mindustry/world/meta/BlockStats.java index 112f431211..c4f9698616 100644 --- a/core/src/io/anuke/mindustry/world/meta/BlockStats.java +++ b/core/src/io/anuke/mindustry/world/meta/BlockStats.java @@ -5,49 +5,71 @@ import com.badlogic.gdx.utils.OrderedMap; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.Liquid; +import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.meta.values.*; import io.anuke.ucore.util.Bundles; import io.anuke.ucore.util.Log; -/**Hold and organizes a list of block stats.*/ -public class BlockStats { +/** + * Hold and organizes a list of block stats. + */ +public class BlockStats{ private static final boolean errorWhenMissing = true; - private OrderedMap> map = new OrderedMap<>(); + private final OrderedMap> map = new OrderedMap<>(); + private final Block block; private boolean dirty; - /**Adds a single float value with this stat, formatted to 2 decimal places.*/ + public BlockStats(Block block){ + this.block = block; + } + + /** + * Adds a single float value with this stat, formatted to 2 decimal places. + */ public void add(BlockStat stat, float value, StatUnit unit){ add(stat, new NumberValue(value, unit)); } - /**Adds a single y/n boolean value.*/ + /** + * Adds a single y/n boolean value. + */ public void add(BlockStat stat, boolean value){ add(stat, new BooleanValue(value)); } - /**Adds an item value.*/ + /** + * Adds an item value. + */ public void add(BlockStat stat, Item item){ add(stat, new ItemValue(new ItemStack(item, 1))); } - /**Adds a liquid value.*/ + /** + * Adds a liquid value. + */ public void add(BlockStat stat, Liquid liquid){ add(stat, new LiquidValue(liquid)); } - /**Adds an item value.*/ + /** + * Adds an item value. + */ public void add(BlockStat stat, ItemStack item){ add(stat, new ItemValue(item)); } - /**Adds a single string value with this stat.*/ + /** + * Adds a single string value with this stat. + */ public void add(BlockStat stat, String format, Object... args){ add(stat, new StringValue(format, args)); } - /**Adds a stat value.*/ + /** + * Adds a stat value. + */ public void add(BlockStat stat, StatValue value){ if(!Bundles.has("text.blocks." + stat.name().toLowerCase())){ if(!errorWhenMissing){ @@ -66,7 +88,7 @@ public class BlockStats { } if(map.containsKey(stat.category) && map.get(stat.category).containsKey(stat)){ - throw new RuntimeException("Duplicate stat entry: \"" +stat + "\""); + throw new RuntimeException("Duplicate stat entry: \"" + stat + "\" in block '" + block.name + "'"); } if(!map.containsKey(stat.category)){ @@ -80,7 +102,7 @@ public class BlockStats { public void remove(BlockStat stat){ if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){ - throw new RuntimeException("No stat entry found: \"" + stat + "\"!"); + throw new RuntimeException("No stat entry found: \"" + stat + "\" in block '" + block.name + "'!"); } map.get(stat.category).remove(stat); @@ -88,11 +110,11 @@ public class BlockStats { dirty = true; } - public OrderedMap> toMap() { + public OrderedMap> toMap(){ //sort stats by index if they've been modified - if(dirty) { + if(dirty){ map.orderedKeys().sort(); - for (Entry> entry : map.entries()) { + for(Entry> entry : map.entries()){ entry.value.orderedKeys().sort(); } diff --git a/core/src/io/anuke/mindustry/world/meta/ContentStatValue.java b/core/src/io/anuke/mindustry/world/meta/ContentStatValue.java index f3aca0b83d..6a8375522e 100644 --- a/core/src/io/anuke/mindustry/world/meta/ContentStatValue.java +++ b/core/src/io/anuke/mindustry/world/meta/ContentStatValue.java @@ -2,6 +2,6 @@ package io.anuke.mindustry.world.meta; import io.anuke.mindustry.game.UnlockableContent; -public interface ContentStatValue extends StatValue { +public interface ContentStatValue extends StatValue{ UnlockableContent[] getValueContent(); } diff --git a/core/src/io/anuke/mindustry/world/meta/StatCategory.java b/core/src/io/anuke/mindustry/world/meta/StatCategory.java index 4932b136fc..ce1ef5b6f2 100644 --- a/core/src/io/anuke/mindustry/world/meta/StatCategory.java +++ b/core/src/io/anuke/mindustry/world/meta/StatCategory.java @@ -1,7 +1,9 @@ package io.anuke.mindustry.world.meta; -/**A specific category for a stat.*/ -public enum StatCategory { +/** + * A specific category for a stat. + */ +public enum StatCategory{ general, power, liquids, diff --git a/core/src/io/anuke/mindustry/world/meta/StatUnit.java b/core/src/io/anuke/mindustry/world/meta/StatUnit.java index c093d31fb3..781f18806f 100644 --- a/core/src/io/anuke/mindustry/world/meta/StatUnit.java +++ b/core/src/io/anuke/mindustry/world/meta/StatUnit.java @@ -2,8 +2,10 @@ package io.anuke.mindustry.world.meta; import io.anuke.ucore.util.Bundles; -/**Defines a unit of measurement for block stats.*/ -public enum StatUnit { +/** + * Defines a unit of measurement for block stats. + */ +public enum StatUnit{ blocks, powerSecond, liquidSecond, diff --git a/core/src/io/anuke/mindustry/world/meta/StatValue.java b/core/src/io/anuke/mindustry/world/meta/StatValue.java index 7a6784ca88..5b95ff6e4d 100644 --- a/core/src/io/anuke/mindustry/world/meta/StatValue.java +++ b/core/src/io/anuke/mindustry/world/meta/StatValue.java @@ -2,9 +2,13 @@ package io.anuke.mindustry.world.meta; import io.anuke.ucore.scene.ui.layout.Table; -/**A base interface for a value of a stat that is displayed.*/ -public interface StatValue { - /**This method should all elements necessary to display this stat to the specified table. - * For example, a stat that is just text would add label to the table. */ +/** + * A base interface for a value of a stat that is displayed. + */ +public interface StatValue{ + /** + * This method should all elements necessary to display this stat to the specified table. + * For example, a stat that is just text would add label to the table. + */ void display(Table table); } diff --git a/core/src/io/anuke/mindustry/world/meta/values/BooleanValue.java b/core/src/io/anuke/mindustry/world/meta/values/BooleanValue.java index ace31e66ce..7adb9bb0b5 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/BooleanValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/BooleanValue.java @@ -3,15 +3,15 @@ package io.anuke.mindustry.world.meta.values; import io.anuke.mindustry.world.meta.StatValue; import io.anuke.ucore.scene.ui.layout.Table; -public class BooleanValue implements StatValue { +public class BooleanValue implements StatValue{ private final boolean value; - public BooleanValue(boolean value) { + public BooleanValue(boolean value){ this.value = value; } @Override - public void display(Table table) { + public void display(Table table){ table.add(!value ? "$text.no" : "$text.yes"); } } diff --git a/core/src/io/anuke/mindustry/world/meta/values/ItemFilterValue.java b/core/src/io/anuke/mindustry/world/meta/values/ItemFilterValue.java index 60ac578f41..f0b4708968 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/ItemFilterValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/ItemFilterValue.java @@ -6,24 +6,24 @@ import io.anuke.mindustry.world.meta.StatValue; import io.anuke.ucore.function.Predicate; import io.anuke.ucore.scene.ui.layout.Table; -public class ItemFilterValue implements StatValue { +public class ItemFilterValue implements StatValue{ private final Predicate filter; - public ItemFilterValue(Predicate filter) { + public ItemFilterValue(Predicate filter){ this.filter = filter; } @Override - public void display(Table table) { + public void display(Table table){ Array list = new Array<>(); for(Item item : Item.all()){ if(filter.test(item)) list.add(item); } - for (int i = 0; i < list.size; i++) { + for(int i = 0; i < list.size; i++){ Item item = list.get(i); - table.addImage(item.region).size(8*3).padRight(2).padLeft(2); + table.addImage(item.region).size(8 * 3).padRight(2).padLeft(2); if(i != list.size - 1){ table.add("/"); } diff --git a/core/src/io/anuke/mindustry/world/meta/values/ItemListValue.java b/core/src/io/anuke/mindustry/world/meta/values/ItemListValue.java index 77890bfe2e..9a236306a3 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/ItemListValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/ItemListValue.java @@ -11,23 +11,23 @@ public class ItemListValue implements ContentStatValue{ private final Item[] items; private final ItemStack[] stacks; - public ItemListValue(Item[] items) { + public ItemListValue(Item[] items){ this.items = items; this.stacks = null; } - public ItemListValue(ItemStack[] stacks) { + public ItemListValue(ItemStack[] stacks){ this.stacks = stacks; this.items = null; } @Override - public UnlockableContent[] getValueContent() { + public UnlockableContent[] getValueContent(){ if(items != null){ return items; - }else { + }else{ Item[] res = new Item[stacks.length]; - for (int i = 0; i < res.length; i++) { + for(int i = 0; i < res.length; i++){ res[i] = stacks[i].item; } return res; @@ -35,14 +35,14 @@ public class ItemListValue implements ContentStatValue{ } @Override - public void display(Table table) { + public void display(Table table){ if(items != null){ for(Item item : items){ - table.addImage(item.region).size(8*3).padRight(5); + table.addImage(item.region).size(8 * 3).padRight(5); } }else{ for(ItemStack stack : stacks){ - table.add(new ItemImage(stack)).size(8*3).padRight(5); + table.add(new ItemImage(stack)).size(8 * 3).padRight(5); } } } diff --git a/core/src/io/anuke/mindustry/world/meta/values/ItemValue.java b/core/src/io/anuke/mindustry/world/meta/values/ItemValue.java index d36dd119d6..d42312c4d1 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/ItemValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/ItemValue.java @@ -7,21 +7,21 @@ import io.anuke.mindustry.ui.ItemImage; import io.anuke.mindustry.world.meta.ContentStatValue; import io.anuke.ucore.scene.ui.layout.Table; -public class ItemValue implements ContentStatValue { +public class ItemValue implements ContentStatValue{ private final ItemStack item; - public ItemValue(ItemStack item) { + public ItemValue(ItemStack item){ this.item = item; } @Override - public UnlockableContent[] getValueContent() { + public UnlockableContent[] getValueContent(){ return new Item[]{item.item}; } @Override - public void display(Table table) { + public void display(Table table){ //TODO better implementation, quantity support - table.add(new ItemImage(item)).size(8*3); + table.add(new ItemImage(item)).size(8 * 3); } } diff --git a/core/src/io/anuke/mindustry/world/meta/values/LiquidFilterValue.java b/core/src/io/anuke/mindustry/world/meta/values/LiquidFilterValue.java index c585a7895f..c8206ad13f 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/LiquidFilterValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/LiquidFilterValue.java @@ -6,24 +6,24 @@ import io.anuke.mindustry.world.meta.StatValue; import io.anuke.ucore.function.Predicate; import io.anuke.ucore.scene.ui.layout.Table; -public class LiquidFilterValue implements StatValue { +public class LiquidFilterValue implements StatValue{ private final Predicate filter; - public LiquidFilterValue(Predicate filter) { + public LiquidFilterValue(Predicate filter){ this.filter = filter; } @Override - public void display(Table table) { + public void display(Table table){ Array list = new Array<>(); for(Liquid item : Liquid.all()){ if(!item.isHidden() && filter.test(item)) list.add(item); } - for (int i = 0; i < list.size; i++) { + for(int i = 0; i < list.size; i++){ Liquid item = list.get(i); - table.addImage(item.getContentIcon()).size(8*3).padRight(2).padLeft(2).padTop(2).padBottom(2); + table.addImage(item.getContentIcon()).size(8 * 3).padRight(2).padLeft(2).padTop(2).padBottom(2); if(i != list.size - 1){ table.add("/"); } diff --git a/core/src/io/anuke/mindustry/world/meta/values/LiquidValue.java b/core/src/io/anuke/mindustry/world/meta/values/LiquidValue.java index 20db91051a..bdee87897e 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/LiquidValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/LiquidValue.java @@ -5,20 +5,20 @@ import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.meta.ContentStatValue; import io.anuke.ucore.scene.ui.layout.Table; -public class LiquidValue implements ContentStatValue { +public class LiquidValue implements ContentStatValue{ private final Liquid liquid; - public LiquidValue(Liquid liquid) { + public LiquidValue(Liquid liquid){ this.liquid = liquid; } @Override - public UnlockableContent[] getValueContent() { + public UnlockableContent[] getValueContent(){ return new UnlockableContent[]{liquid}; } @Override - public void display(Table table) { - table.addImage(liquid.getContentIcon()).size(8*3); + public void display(Table table){ + table.addImage(liquid.getContentIcon()).size(8 * 3); } } diff --git a/core/src/io/anuke/mindustry/world/meta/values/NumberValue.java b/core/src/io/anuke/mindustry/world/meta/values/NumberValue.java index 65f6a48a78..0dd73ac91f 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/NumberValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/NumberValue.java @@ -5,13 +5,15 @@ import io.anuke.mindustry.world.meta.StatValue; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Strings; -/**A stat that is a number with a unit attacked. - * The number is rounded to 2 decimal places by default.*/ +/** + * A stat that is a number with a unit attacked. + * The number is rounded to 2 decimal places by default. + */ public class NumberValue implements StatValue{ private final StatUnit unit; private final float value; - public NumberValue(float value, StatUnit unit) { + public NumberValue(float value, StatUnit unit){ this.unit = unit; this.value = value; @@ -21,8 +23,8 @@ public class NumberValue implements StatValue{ } @Override - public void display(Table table) { - float diff = Math.abs((int)value - value); + public void display(Table table){ + float diff = Math.abs((int) value - value); int precision = diff <= 0.01f ? 0 : diff <= 0.1f ? 1 : 2; table.add(Strings.toFixed(value, precision)); diff --git a/core/src/io/anuke/mindustry/world/meta/values/StringValue.java b/core/src/io/anuke/mindustry/world/meta/values/StringValue.java index 1e3ab92fdd..1a0bc458d0 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/StringValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/StringValue.java @@ -4,15 +4,15 @@ import io.anuke.mindustry.world.meta.StatValue; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.util.Strings; -public class StringValue implements StatValue { +public class StringValue implements StatValue{ private final String value; - public StringValue(String value, Object... args) { + public StringValue(String value, Object... args){ this.value = Strings.formatArgs(value, args); } @Override - public void display(Table table) { + public void display(Table table){ table.add(value); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/BlockModule.java b/core/src/io/anuke/mindustry/world/modules/BlockModule.java similarity index 74% rename from core/src/io/anuke/mindustry/world/blocks/BlockModule.java rename to core/src/io/anuke/mindustry/world/modules/BlockModule.java index c30e571dd8..225b7c3e9d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BlockModule.java +++ b/core/src/io/anuke/mindustry/world/modules/BlockModule.java @@ -1,10 +1,11 @@ -package io.anuke.mindustry.world.blocks; +package io.anuke.mindustry.world.modules; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -public abstract class BlockModule { +public abstract class BlockModule{ public abstract void write(DataOutput stream) throws IOException; + public abstract void read(DataInput stream) throws IOException; } diff --git a/core/src/io/anuke/mindustry/world/modules/ConsumeModule.java b/core/src/io/anuke/mindustry/world/modules/ConsumeModule.java new file mode 100644 index 0000000000..40d06f6853 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/modules/ConsumeModule.java @@ -0,0 +1,41 @@ +package io.anuke.mindustry.world.modules; + +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.world.consumers.Consume; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class ConsumeModule extends BlockModule{ + private boolean valid; + + public void update(TileEntity entity){ + boolean prevValid = valid; + valid = true; + + for(Consume cons : entity.tile.block().consumes.all()){ + if(cons.isUpdate() && prevValid && entity.tile.block().shouldConsume(entity.tile) && cons.valid(entity.getTile().block(), entity)){ + cons.update(entity.getTile().block(), entity); + } + + if(!cons.isOptional()){ + valid &= cons.valid(entity.getTile().block(), entity); + } + } + } + + public boolean valid(){ + return valid; + } + + @Override + public void write(DataOutput stream) throws IOException{ + stream.writeBoolean(valid); + } + + @Override + public void read(DataInput stream) throws IOException{ + valid = stream.readBoolean(); + } +} diff --git a/core/src/io/anuke/mindustry/world/modules/InventoryModule.java b/core/src/io/anuke/mindustry/world/modules/InventoryModule.java new file mode 100644 index 0000000000..85a349f334 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/modules/InventoryModule.java @@ -0,0 +1,145 @@ +package io.anuke.mindustry.world.modules; + +import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.type.ItemStack; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Arrays; + +public class InventoryModule extends BlockModule{ + private int[] items = new int[Item.all().size]; + private int total; + + public void forEach(ItemConsumer cons){ + for(int i = 0; i < items.length; i++){ + if(items[i] > 0){ + cons.accept(Item.getByID(i), items[i]); + } + } + } + + public float sum(ItemCalculator calc){ + float sum = 0f; + for(int i = 0; i < items.length; i++){ + if(items[i] > 0){ + sum += calc.get(Item.getByID(i), items[i]); + } + } + return sum; + } + + public boolean has(Item item){ + return get(item) > 0; + } + + public boolean has(Item item, int amount){ + return get(item) >= amount; + } + + public boolean has(ItemStack[] stacks){ + for(ItemStack stack : stacks){ + if(!has(stack.item, stack.amount)) return false; + } + return true; + } + + public boolean has(ItemStack[] stacks, float amountScaling){ + for(ItemStack stack : stacks){ + if(!has(stack.item, (int) (stack.amount * amountScaling))) return false; + } + return true; + } + + /** + * Returns true if this entity has at least one of each item in each stack. + */ + public boolean hasOne(ItemStack[] stacks){ + for(ItemStack stack : stacks){ + if(!has(stack.item, 1)) return false; + } + return true; + } + + public int total(){ + return total; + } + + public Item take(){ + for(int i = 0; i < items.length; i++){ + if(items[i] > 0){ + items[i]--; + total--; + return Item.getByID(i); + } + } + return null; + } + + public int get(Item item){ + return items[item.id]; + } + + public void set(Item item, int amount){ + total += (amount - items[item.id]); + items[item.id] = amount; + } + + public void add(Item item, int amount){ + items[item.id] += amount; + total += amount; + } + + public void remove(Item item, int amount){ + items[item.id] -= amount; + total -= amount; + } + + public void remove(ItemStack stack){ + remove(stack.item, stack.amount); + } + + public void clear(){ + Arrays.fill(items, 0); + total = 0; + } + + @Override + public void write(DataOutput stream) throws IOException{ + byte amount = 0; + for(int item : items){ + if(item > 0) amount++; + } + + stream.writeByte(amount); //amount of items + + for(int i = 0; i < items.length; i++){ + if(items[i] > 0){ + stream.writeByte(i); //item ID + stream.writeInt(items[i]); //item amount + } + } + } + + @Override + public void read(DataInput stream) throws IOException{ + byte count = stream.readByte(); + total = 0; + + for(int j = 0; j < count; j++){ + int itemid = stream.readByte(); + int itemamount = stream.readInt(); + items[itemid] = itemamount; + total += itemamount; + } + } + + public interface ItemConsumer{ + void accept(Item item, float amount); + } + + public interface ItemCalculator{ + float get(Item item, int amount); + } +} diff --git a/core/src/io/anuke/mindustry/world/modules/LiquidModule.java b/core/src/io/anuke/mindustry/world/modules/LiquidModule.java new file mode 100644 index 0000000000..12c87f1307 --- /dev/null +++ b/core/src/io/anuke/mindustry/world/modules/LiquidModule.java @@ -0,0 +1,103 @@ +package io.anuke.mindustry.world.modules; + +import io.anuke.mindustry.type.Liquid; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class LiquidModule extends BlockModule{ + private float[] liquids = new float[Liquid.all().size]; + private float total; + private Liquid current = Liquid.getByID(0); + + /** + * Returns total amount of liquids. + */ + public float total(){ + return total; + } + + /** + * Last recieved or loaded liquid. Only valid for liquid modules with 1 type of liquid. + */ + public Liquid current(){ + return current; + } + + public float currentAmount(){ + return liquids[current.id]; + } + + public float get(Liquid liquid){ + return liquids[liquid.id]; + } + + public void add(Liquid liquid, float amount){ + liquids[liquid.id] += amount; + total += amount; + current = liquid; + } + + public void remove(Liquid liquid, float amount){ + add(liquid, -amount); + } + + public void forEach(LiquidConsumer cons){ + for(int i = 0; i < liquids.length; i++){ + if(liquids[i] > 0){ + cons.accept(Liquid.getByID(i), liquids[i]); + } + } + } + + public float sum(LiquidCalculator calc){ + float sum = 0f; + for(int i = 0; i < liquids.length; i++){ + if(liquids[i] > 0){ + sum += calc.get(Liquid.getByID(i), liquids[i]); + } + } + return sum; + } + + @Override + public void write(DataOutput stream) throws IOException{ + byte amount = 0; + for(float liquid : liquids){ + if(liquid > 0) amount++; + } + + stream.writeByte(amount); //amount of liquids + + for(int i = 0; i < liquids.length; i++){ + if(liquids[i] > 0){ + stream.writeByte(i); //liquid ID + stream.writeFloat(liquids[i]); //item amount + } + } + } + + @Override + public void read(DataInput stream) throws IOException{ + byte count = stream.readByte(); + + for(int j = 0; j < count; j++){ + int liquidid = stream.readByte(); + float amount = stream.readFloat(); + liquids[liquidid] = amount; + if(amount > 0){ + current = Liquid.getByID(liquidid); + } + this.total += amount; + } + } + + public interface LiquidConsumer{ + void accept(Liquid liquid, float amount); + } + + public interface LiquidCalculator{ + float get(Liquid liquid, float amount); + } +} diff --git a/core/src/io/anuke/mindustry/world/blocks/modules/PowerModule.java b/core/src/io/anuke/mindustry/world/modules/PowerModule.java similarity index 82% rename from core/src/io/anuke/mindustry/world/blocks/modules/PowerModule.java rename to core/src/io/anuke/mindustry/world/modules/PowerModule.java index 91c38f521f..320408ec5e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/modules/PowerModule.java +++ b/core/src/io/anuke/mindustry/world/modules/PowerModule.java @@ -1,6 +1,4 @@ -package io.anuke.mindustry.world.blocks.modules; - -import io.anuke.mindustry.world.blocks.BlockModule; +package io.anuke.mindustry.world.modules; import java.io.DataInput; import java.io.DataOutput; @@ -28,7 +26,7 @@ public class PowerModule extends BlockModule{ } @Override - public void write(DataOutput stream) throws IOException { + public void write(DataOutput stream) throws IOException{ stream.writeFloat(amount); } diff --git a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java index 220400590b..c611915dfe 100644 --- a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java +++ b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.desktop; +import io.anuke.mindustry.io.Version; import io.anuke.mindustry.net.Net; import io.anuke.ucore.core.Settings; import io.anuke.ucore.util.Strings; @@ -10,31 +11,37 @@ import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; -public class CrashHandler { +public class CrashHandler{ public static void handle(Throwable e){ //TODO send full error report to server via HTTP e.printStackTrace(); + boolean netActive = false, netServer = false; + //attempt to close connections, if applicable try{ + netActive = Net.active(); + netServer = Net.server(); Net.dispose(); - }catch (Throwable p){ + }catch(Throwable p){ p.printStackTrace(); } //don't create crash logs for me (anuke), as it's expected if(System.getProperty("user.name").equals("anuke")) return; - String header = ""; + String header = "--CRASH REPORT--\n"; try{ - header += "--GAME INFO-- \n"; - header += "Multithreading: " + Settings.getBool("multithread")+ "\n"; - header += "Net Active: " + Net.active()+ "\n"; - header += "Net Server: " + Net.server()+ "\n"; - header += "OS: " + System.getProperty("os.name")+ "\n----\n"; - }catch (Throwable e4){ + header += "--GAME INFO--\n"; + header += "Build: " + Version.build + "\n"; + header += "Net Active: " + netActive + "\n"; + header += "Net Server: " + netServer + "\n"; + header += "OS: " + System.getProperty("os.name") + "\n"; + header += "Multithreading: " + Settings.getBool("multithread") + "\n----\n"; + }catch(Throwable e4){ + header += "\n--error getting additional info--\n"; e4.printStackTrace(); } @@ -47,17 +54,17 @@ public class CrashHandler { //try to write it try{ filename = "crash-report-" + new SimpleDateFormat("dd-MM-yy h.mm.ss").format(new Date()) + ".txt"; - Files.write(Paths.get(filename), result.getBytes()); - }catch (Throwable i){ + Files.write(Paths.get(System.getProperty("user.home"), "mindustry-crash-reports", filename), result.getBytes()); + }catch(Throwable i){ i.printStackTrace(); failed = true; } try{ javax.swing.JOptionPane.showMessageDialog(null, "An error has occured: \n" + result + "\n\n" + - (!failed ? "A crash report has been written to " + new File(filename).getAbsolutePath() + ".\nPlease send this file to the developer!" - : "Failed to generate crash report.\nPlease send an image of this crash log to the developer!")); - }catch (Throwable i){ + (!failed ? "A crash report has been written to " + new File(filename).getAbsolutePath() + ".\nPlease send this file to the developer!" + : "Failed to generate crash report.\nPlease send an image of this crash log to the developer!")); + }catch(Throwable i){ i.printStackTrace(); //what now? } diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java index cfd729a066..3c21144f6b 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java @@ -30,78 +30,76 @@ import static io.anuke.mindustry.Vars.*; public class DesktopLauncher extends Lwjgl3Application{ ObjectMap prefmap; - - public static void main (String[] arg) { - - Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); - config.setTitle("Mindustry"); - config.setMaximized(true); - config.setWindowedMode(960, 540); - config.setWindowIcon("sprites/icon.png"); - if(OS.isMac) { - Application.getApplication().setOpenFileHandler(e -> { - List list = e.getFiles(); - - File target = (File)list.get(0); - - Gdx.app.postRunnable(() -> { - FileHandle file = OS.getAppDataDirectory("Mindustry").child("tmp").child(target.getName()); - - Gdx.files.absolute(target.getAbsolutePath()).copyTo(file); - - if(file.extension().equalsIgnoreCase(saveExtension)){ //open save - - if(SaveIO.isSaveValid(file)){ - try{ - SaveSlot slot = control.getSaves().importSave(file); - ui.load.runLoadSave(slot); - }catch (IOException e2){ - ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e2, false))); - } - }else{ - ui.showError("$text.save.import.invalid"); - } - - }else if(file.extension().equalsIgnoreCase(mapExtension)){ //open map - Gdx.app.postRunnable(() -> { - if (!ui.editor.isShown()) { - ui.editor.show(); - } - - ui.editor.beginEditMap(file.read()); - }); - } - }); - }); - } - - Platform.instance = new DesktopPlatform(arg); - - Net.setClientProvider(new KryoClient()); - Net.setServerProvider(new KryoServer()); - - try { - new DesktopLauncher(new Mindustry(), config); - }catch (Throwable e){ - CrashHandler.handle(e); - } - } - - public DesktopLauncher(ApplicationListener listener, Lwjgl3ApplicationConfiguration config) { + public DesktopLauncher(ApplicationListener listener, Lwjgl3ApplicationConfiguration config){ super(listener, config); } - @Override - public Preferences getPreferences(String name) { - String prefsDirectory = OS.getAppDataDirectoryString("Mindustry"); + public static void main(String[] arg){ + try{ + Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); + config.setTitle("Mindustry"); + config.setMaximized(true); + config.setWindowedMode(960, 540); + config.setWindowIcon("sprites/icon.png"); - if(prefmap == null){ - prefmap = new ObjectMap<>(); + if(OS.isMac){ + Application.getApplication().setOpenFileHandler(e -> { + List list = e.getFiles(); + + File target = (File) list.get(0); + + Gdx.app.postRunnable(() -> { + FileHandle file = OS.getAppDataDirectory("Mindustry").child("tmp").child(target.getName()); + + Gdx.files.absolute(target.getAbsolutePath()).copyTo(file); + + if(file.extension().equalsIgnoreCase(saveExtension)){ //open save + + if(SaveIO.isSaveValid(file)){ + try{ + SaveSlot slot = control.getSaves().importSave(file); + ui.load.runLoadSave(slot); + }catch(IOException e2){ + ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e2, false))); + } + }else{ + ui.showError("$text.save.import.invalid"); + } + + }else if(file.extension().equalsIgnoreCase(mapExtension)){ //open map + Gdx.app.postRunnable(() -> { + if(!ui.editor.isShown()){ + ui.editor.show(); + } + + ui.editor.beginEditMap(file.read()); + }); + } + }); + }); + } + + Platform.instance = new DesktopPlatform(arg); + + Net.setClientProvider(new KryoClient()); + Net.setServerProvider(new KryoServer()); + new DesktopLauncher(new Mindustry(), config); + }catch(Throwable e){ + CrashHandler.handle(e); + } + } + + @Override + public Preferences getPreferences(String name){ + String prefsDirectory = OS.getAppDataDirectoryString("Mindustry"); + + if(prefmap == null){ + prefmap = new ObjectMap<>(); } - if(prefmap.containsKey(name)){ - return prefmap.get(name); + if(prefmap.containsKey(name)){ + return prefmap.get(name); }else{ Preferences prefs = new BinaryPreferences(new Lwjgl3FileHandle(new File(prefsDirectory, name), FileType.Absolute)); prefmap.put(name, prefs); diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java index 0f2c27078d..6511f3fe08 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java @@ -27,7 +27,7 @@ import java.util.Locale; import static io.anuke.mindustry.Vars.*; -public class DesktopPlatform extends Platform { +public class DesktopPlatform extends Platform{ final static boolean useDiscord = OS.is64Bit; final static String applicationId = "398246104468291591"; final static DateFormat format = SimpleDateFormat.getDateTimeInstance(); @@ -36,16 +36,16 @@ public class DesktopPlatform extends Platform { public DesktopPlatform(String[] args){ this.args = args; - Vars.testMobile = Array.with(args).contains("-testMobile", false); + Vars.testMobile = isDebug() && Array.with(args).contains("-testMobile", false); - if(useDiscord) { + if(useDiscord){ DiscordEventHandlers handlers = new DiscordEventHandlers(); DiscordRPC.INSTANCE.Discord_Initialize(applicationId, handlers, true, ""); } } @Override - public void showFileChooser(String text, String content, Consumer cons, boolean open, String filter) { + public void showFileChooser(String text, String content, Consumer cons, boolean open, String filter){ new FileChooser(text, file -> file.extension().equalsIgnoreCase(filter), open, cons).show(); } @@ -70,7 +70,7 @@ public class DesktopPlatform extends Platform { } @Override - public void updateRPC() { + public void updateRPC(){ if(!useDiscord) return; @@ -89,7 +89,7 @@ public class DesktopPlatform extends Platform { }else{ if(ui.editor != null && ui.editor.isShown()){ presence.state = "In Editor"; - }else { + }else{ presence.state = "In Menu"; } } @@ -100,26 +100,27 @@ public class DesktopPlatform extends Platform { } @Override - public void onGameExit() { + public void onGameExit(){ if(useDiscord) DiscordRPC.INSTANCE.Discord_Shutdown(); } @Override - public boolean isDebug() { - return args.length > 0 && args[0].equalsIgnoreCase("-debug"); + public boolean isDebug(){ + return args.length > 0 && args[0].equalsIgnoreCase("-debug_" + getUUID().hashCode()); } @Override - public ThreadProvider getThreadProvider() { + public ThreadProvider getThreadProvider(){ return new DefaultThreadImpl(); } @Override - public String getUUID() { - try { + public String getUUID(){ + try{ Enumeration e = NetworkInterface.getNetworkInterfaces(); NetworkInterface out; - for(out = e.nextElement(); out.getHardwareAddress() == null && e.hasMoreElements() && validAddress(out.getHardwareAddress()); out = e.nextElement()); + for(out = e.nextElement(); out.getHardwareAddress() == null && e.hasMoreElements() && validAddress(out.getHardwareAddress()); out = e.nextElement()) + ; byte[] bytes = out.getHardwareAddress(); byte[] result = new byte[8]; @@ -130,7 +131,7 @@ public class DesktopPlatform extends Platform { if(str.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID."); return str; - }catch (Exception e){ + }catch(Exception e){ return super.getUUID(); } } diff --git a/gradle.properties b/gradle.properties index 93e3c4269f..d8e2a1210f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,5 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms512m -Xmx1536m -org.gradle.configureondemand=true android.enableAapt2=true android.injected.build.model.only.versioned=3 android.enableD8=true diff --git a/html/src/io/anuke/mindustry/client/HtmlLauncher.java b/html/src/io/anuke/mindustry/client/HtmlLauncher.java index 35b1ea0748..208e24b976 100644 --- a/html/src/io/anuke/mindustry/client/HtmlLauncher.java +++ b/html/src/io/anuke/mindustry/client/HtmlLauncher.java @@ -218,6 +218,16 @@ public class HtmlLauncher extends GwtApplication { public InputStream read() { return stream; } + + @Override + public String nameWithoutExtension() { + return "unknown"; + } + + @Override + public String name() { + return "unknown"; + } }); } } diff --git a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java b/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java index 7e2b8670f6..ff2d80c4b2 100644 --- a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java +++ b/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java @@ -1,14 +1,8 @@ package io.anuke.kryonet; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; -import io.anuke.ucore.entities.EntityGroup; -import io.anuke.ucore.entities.EntityGroup.EntityContainer; -import io.anuke.ucore.entities.trait.Entity; import io.anuke.ucore.util.Log; -import java.util.Iterator; -import java.util.concurrent.CopyOnWriteArrayList; - public class DefaultThreadImpl implements ThreadProvider { private Thread thread; @@ -54,42 +48,4 @@ public class DefaultThreadImpl implements ThreadProvider { object.notify(); } - @Override - public void switchContainer(EntityGroup group) { - group.setContainer(new ConcurrentContainer<>()); - } - - static class ConcurrentContainer implements EntityContainer{ - private CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); - - @Override - public int size() { - return list.size(); - } - - @Override - public void add(T item) { - list.add(item); - } - - @Override - public void clear() { - list.clear(); - } - - @Override - public void remove(T item) { - list.remove(item); - } - - @Override - public T get(int index) { - return list.get(index); - } - - @Override - public Iterator iterator() { - return list.iterator(); - } - } } diff --git a/packer/build.gradle b/packer/build.gradle index 64b054f422..06ce5fd606 100644 --- a/packer/build.gradle +++ b/packer/build.gradle @@ -43,3 +43,12 @@ task generateSprites(dependsOn: classes, type: JavaExec) { standardInput = System.in workingDir = textureFolder } + +task fixBundles(dependsOn: classes, type: JavaExec) { + file(textureFolder).mkdirs() + + main = "io.anuke.mindustry.BundleLauncher" + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = "../core/assets/bundles/" +} diff --git a/packer/src/io/anuke/mindustry/BundleLauncher.java b/packer/src/io/anuke/mindustry/BundleLauncher.java new file mode 100644 index 0000000000..8160e39dc5 --- /dev/null +++ b/packer/src/io/anuke/mindustry/BundleLauncher.java @@ -0,0 +1,74 @@ +package io.anuke.mindustry; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.OrderedMap; +import com.badlogic.gdx.utils.PropertiesUtils; +import io.anuke.ucore.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class BundleLauncher { + + public static void main(String[] args) throws Exception{ + File file = new File("bundle.properties"); + OrderedMap base = new OrderedMap<>(); + PropertiesUtils.load(base, new InputStreamReader(new FileInputStream(file))); + Array removals = new Array<>(); + + Files.walk(Paths.get("")).forEach(child -> { + try { + if (child.getFileName().toString().equals("bundle.properties") || Files.isDirectory(child) || child.toString().contains("output")) return; + + Log.info("Parsing bundle: {0}", child); + + OrderedMap other = new OrderedMap<>(); + PropertiesUtils.load(other, Files.newBufferedReader(child)); + removals.clear(); + + for(String key : other.orderedKeys()){ + if(!base.containsKey(key)){ + removals.add(key); + Log.info("&lr- Removing unused key '{0}'...", key); + } + } + Log.info("&lr{0} keys removed.", removals.size); + for(String s : removals){ + other.remove(s); + } + + int added = 0; + + for(String key : base.orderedKeys()){ + if(!other.containsKey(key)){ + other.put(key, base.get(key)); + added ++; + Log.info("&lc- Adding missing key '{0}'...", key); + } + } + + Path output = child.resolveSibling("output/" + child.getFileName()); + + Log.info("&lc{0} keys added.", added); + Log.info("Writing bundle to {0}", output); + StringBuilder result = new StringBuilder(); + for(ObjectMap.Entry e : other.entries()){ + result.append(e.toString().replace("\\", "\\\\").replace("\n", "\\n")); + result.append("\n"); + } + Files.write(child, result.toString().getBytes()); + //PropertiesUtils.store(other, Files.newBufferedWriter(output), null); + + }catch (IOException e){ + throw new RuntimeException(e); + } + }); + } + +} diff --git a/server/src/io/anuke/mindustry/server/MindustryServer.java b/server/src/io/anuke/mindustry/server/MindustryServer.java index c82c4a5695..fdd846c7f3 100644 --- a/server/src/io/anuke/mindustry/server/MindustryServer.java +++ b/server/src/io/anuke/mindustry/server/MindustryServer.java @@ -11,7 +11,7 @@ import io.anuke.ucore.modules.ModuleCore; import static io.anuke.mindustry.Vars.*; -public class MindustryServer extends ModuleCore { +public class MindustryServer extends ModuleCore{ private String[] args; public MindustryServer(String[] args){ diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index 99c93b1b6d..5e310c46f4 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -33,21 +33,23 @@ import java.util.Scanner; import static io.anuke.mindustry.Vars.*; import static io.anuke.ucore.util.Log.*; -public class ServerControl extends Module { +public class ServerControl extends Module{ private final CommandHandler handler = new CommandHandler(""); private ShuffleMode mode; public ServerControl(String[] args){ Settings.defaultList( - "shufflemode", "normal", - "bans", "", - "admins", "" + "shufflemode", "normal", + "bans", "", + "admins", "" ); mode = ShuffleMode.valueOf(Settings.getString("shufflemode")); - Effects.setScreenShakeProvider((a, b) -> {}); - Effects.setEffectProvider((a, b, c, d, e, f) -> {}); + Effects.setScreenShakeProvider((a, b) -> { + }); + Effects.setEffectProvider((a, b, c, d, e, f) -> { + }); Sounds.setHeadless(true); String[] commands = {}; @@ -79,16 +81,16 @@ public class ServerControl extends Module { netServer.kick(connection.id, KickReason.gameover); } - if (mode != ShuffleMode.off) { - if(world.maps().all().size > 0) { + if(mode != ShuffleMode.off){ + if(world.maps().all().size > 0){ Array maps = mode == ShuffleMode.both ? world.maps().all() : mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps(); Map previous = world.getMap(); Map map = previous; - while (map == previous) map = maps.random(); + while(map == previous) map = maps.random(); - if(map != null) { + if(map != null){ info("Selected next map to be {0}.", map.name); state.set(State.playing); @@ -147,11 +149,11 @@ public class ServerControl extends Module { Map result = null; - if(arg.length > 0) { + if(arg.length > 0){ GameMode mode; try{ mode = GameMode.valueOf(arg[0]); - }catch (IllegalArgumentException e){ + }catch(IllegalArgumentException e){ err("No gamemode '{0}' found.", arg[0]); return; } @@ -159,14 +161,14 @@ public class ServerControl extends Module { info("Loading map..."); state.mode = mode; - if(arg.length > 1) { + if(arg.length > 1){ String search = arg[1]; - for (Map map : world.maps().all()) { - if (map.name.equalsIgnoreCase(search)) + for(Map map : world.maps().all()){ + if(map.name.equalsIgnoreCase(search)) result = map; } - if (result == null) { + if(result == null){ err("No map with name &y'{0}'&lr found.", search); return; } @@ -205,18 +207,18 @@ public class ServerControl extends Module { if(state.mode.disableWaveTimer){ info("&ly{0} enemies.", unitGroups[Team.red.ordinal()].size()); }else{ - info("&ly{0} seconds until next wave.", (int)(state.wavetime / 60)); + info("&ly{0} seconds until next wave.", (int) (state.wavetime / 60)); } - if(playerGroup.size() > 0) { + if(playerGroup.size() > 0){ info("&lyPlayers: {0}", playerGroup.size()); - for (Player p : playerGroup.all()) { + for(Player p : playerGroup.all()){ print(" &y" + p.name); } }else{ info("&lyNo players connected."); } - info("&lbFPS: {0}", (int)(60f/Timers.delta())); + info("&lbFPS: {0}", (int) (60f / Timers.delta())); } }); @@ -224,9 +226,9 @@ public class ServerControl extends Module { if(state.is(State.menu)){ info("&lyServer is closed."); }else{ - if(playerGroup.size() > 0) { + if(playerGroup.size() > 0){ info("&lyPlayers: {0}", playerGroup.size()); - for (Player p : playerGroup.all()) { + for(Player p : playerGroup.all()){ print(" &y{0} / Connection {1} / IP: {2}", p.name, p.con.id, p.con.address); } }else{ @@ -236,7 +238,7 @@ public class ServerControl extends Module { }); handler.register("say", "", "Send a message to all players.", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Not hosting. Host a game first."); return; } @@ -251,7 +253,7 @@ public class ServerControl extends Module { Difficulty diff = Difficulty.valueOf(arg[0]); state.difficulty = diff; info("Difficulty set to '{0}'.", arg[0]); - }catch (IllegalArgumentException e){ + }catch(IllegalArgumentException e){ err("No difficulty with name '{0}' found.", arg[0]); } }); @@ -286,13 +288,13 @@ public class ServerControl extends Module { err("Incorrect command usage."); } - if(arg.length >= 2) { - try { + if(arg.length >= 2){ + try{ int maxbreak = Integer.parseInt(arg[1]); int cooldown = (arg.length >= 3 ? Integer.parseInt(arg[2]) : Administration.defaultBreakCooldown); netServer.admins.setAntiGriefParams(maxbreak, cooldown); info("Anti-grief parameters set."); - } catch (NumberFormatException e) { + }catch(NumberFormatException e){ err("Invalid number format."); } } @@ -323,13 +325,13 @@ public class ServerControl extends Module { Settings.putString("shufflemode", arg[0]); Settings.save(); info("Shuffle mode set to '{0}'.", arg[0]); - }catch (Exception e){ + }catch(Exception e){ err("Unknown shuffle mode '{0}'.", arg[0]); } }); handler.register("kick", "", "Kick a person by name.", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Not hosting a game yet. Calm down."); return; } @@ -352,7 +354,7 @@ public class ServerControl extends Module { }); handler.register("ban", "", "Ban a person by name.", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Can't ban people by name with no players."); return; } @@ -397,7 +399,7 @@ public class ServerControl extends Module { Log.info("&lmBanned players [IP]:"); for(String string : ipbans){ PlayerInfo info = netServer.admins.findByIP(string); - if(info != null) { + if(info != null){ Log.info(" &lm '{0}' / Last known name: '{1}' / ID: '{2}'", string, info.lastName, info.id); }else{ Log.info(" &lm '{0}' (No known name or info)", string); @@ -407,7 +409,7 @@ public class ServerControl extends Module { }); handler.register("banip", "", "Ban a person by IP.", arg -> { - if(netServer.admins.banPlayerIP(arg[0])) { + if(netServer.admins.banPlayerIP(arg[0])){ info("Banned player by IP: {0}.", arg[0]); for(Player player : playerGroup.all()){ @@ -423,7 +425,7 @@ public class ServerControl extends Module { }); handler.register("banid", "", "Ban a person by their unique ID.", arg -> { - if(netServer.admins.banPlayerID(arg[0])) { + if(netServer.admins.banPlayerID(arg[0])){ info("Banned player by ID: {0}.", arg[0]); for(Player player : playerGroup.all()){ @@ -438,7 +440,7 @@ public class ServerControl extends Module { }); handler.register("unbanip", "", "Completely unban a person by IP.", arg -> { - if(netServer.admins.unbanPlayerIP(arg[0])) { + if(netServer.admins.unbanPlayerIP(arg[0])){ info("Unbanned player by IP: {0}.", arg[0]); }else{ err("That IP is not banned!"); @@ -446,7 +448,7 @@ public class ServerControl extends Module { }); handler.register("unbanid", "", "Completely unban a person by ID.", arg -> { - if(netServer.admins.unbanPlayerID(arg[0])) { + if(netServer.admins.unbanPlayerID(arg[0])){ info("&lmUnbanned player by ID: {0}.", arg[0]); }else{ err("That IP is not banned!"); @@ -454,7 +456,7 @@ public class ServerControl extends Module { }); handler.register("admin", "", "Make a user admin", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Open the server first."); return; } @@ -478,7 +480,7 @@ public class ServerControl extends Module { }); handler.register("unadmin", "", "Removes admin status from a player", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Open the server first."); return; } @@ -515,7 +517,7 @@ public class ServerControl extends Module { }); handler.register("runwave", "Trigger the next wave.", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Not hosting. Host a game first."); }else{ logic.runWave(); @@ -562,19 +564,19 @@ public class ServerControl extends Module { }); handler.register("griefers", "[min-break:place-ratio] [min-breakage]", "Find possible griefers currently online.", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Open the server first."); return; } - try { + try{ float ratio = arg.length > 0 ? Float.parseFloat(arg[0]) : 0.5f; int minbreak = arg.length > 1 ? Integer.parseInt(arg[1]) : 100; boolean found = false; - for (Player player : playerGroup.all()) { + for(Player player : playerGroup.all()){ TraceInfo info = netServer.admins.getTraceByID(player.uuid); if(info.totalBlocksBroken >= minbreak && info.totalBlocksBroken / Math.max(info.totalBlocksPlaced, 1f) >= ratio){ info("&ly - Player '{0}' / UUID &lm{1}&ly found: &lc{2}&ly broken and &lc{3}&ly placed.", @@ -583,19 +585,19 @@ public class ServerControl extends Module { } } - if (!found) { + if(!found){ info("No griefers matching the criteria have been found."); } - }catch (NumberFormatException e){ + }catch(NumberFormatException e){ err("Invalid number format."); } }); handler.register("gameover", "Force a game over.", arg -> { if(state.is(State.menu)){ - info("Not playing a map."); - return; + info("Not playing a map."); + return; } Events.fire(GameOverEvent.class); @@ -616,10 +618,10 @@ public class ServerControl extends Module { if(tile.entity != null){ Array arr = tile.block().getDebugInfo(tile); StringBuilder result = new StringBuilder(); - for(int i = 0; i < arr.size/2; i ++){ - result.append(arr.get(i*2)); + for(int i = 0; i < arr.size / 2; i++){ + result.append(arr.get(i * 2)); result.append(": "); - result.append(arr.get(i*2 + 1)); + result.append(arr.get(i * 2 + 1)); result.append("\n"); } Log.info("&ly{0}", result); @@ -629,7 +631,7 @@ public class ServerControl extends Module { }else{ Log.info("No tile at that location."); } - }catch (NumberFormatException e){ + }catch(NumberFormatException e){ Log.err("Invalid coordinates passed."); } }); @@ -639,7 +641,7 @@ public class ServerControl extends Module { Array infos = netServer.admins.findByName(arg[0], checkAll); - if(infos.size == 1) { + if(infos.size == 1){ PlayerInfo info = infos.peek(); Log.info("&lcTrace info for player '{0}' / UUID {1}:", info.lastName, info.id); Log.info(" &lyall names used: {0}", info.names); @@ -665,7 +667,7 @@ public class ServerControl extends Module { Array infos = netServer.admins.findByIPs(arg[0]); - if(infos.size == 1) { + if(infos.size == 1){ PlayerInfo info = infos.peek(); Log.info("&lcTrace info for player '{0}' / UUID {1}:", info.lastName, info.id); Log.info(" &lyall names used: {0}", info.names); @@ -707,7 +709,7 @@ public class ServerControl extends Module { }); handler.register("trace", "", "Trace a player's actions", arg -> { - if(!state.is(State.playing)) { + if(!state.is(State.playing)){ err("Open the server first."); return; } @@ -724,7 +726,7 @@ public class ServerControl extends Module { if(target != null){ TraceInfo info = netServer.admins.getTraceByID(target.uuid); Log.info("&lcTrace info for player '{0}':", target.name); - Log.info(" &lyEntity ID: {0}", info. playerid); + Log.info(" &lyEntity ID: {0}", info.playerid); Log.info(" &lyIP: {0}", info.ip); Log.info(" &lyUUID: {0}", info.uuid); Log.info(" &lycustom client: {0}", info.modclient); @@ -741,27 +743,27 @@ public class ServerControl extends Module { } }); - handler.register("rollback", "", "Rollback the block edits in the world", arg -> { - if(!state.is(State.playing)) { - err("Open the server first."); - return; - } + handler.register("rollback", "", "Rollback the block edits in the world", arg -> { + if(!state.is(State.playing)){ + err("Open the server first."); + return; + } - if(!Strings.canParsePostiveInt(arg[0])) { - err("Please input a valid, positive, number of times to rollback"); - return; - } + if(!Strings.canParsePostiveInt(arg[0])){ + err("Please input a valid, positive, number of times to rollback"); + return; + } - int rollbackTimes = Integer.valueOf(arg[0]); - IntMap> editLogs = netServer.admins.getEditLogs(); - if(editLogs.size == 0){ - err("Nothing to rollback!"); - return; - } + int rollbackTimes = Integer.valueOf(arg[0]); + IntMap> editLogs = netServer.admins.getEditLogs(); + if(editLogs.size == 0){ + err("Nothing to rollback!"); + return; + } - //netServer.admins.rollbackWorld(rollbackTimes); - info("Rollback done!"); - }); + //netServer.admins.rollbackWorld(rollbackTimes); + info("Rollback done!"); + }); } private void readCommands(){ @@ -772,7 +774,7 @@ public class ServerControl extends Module { Gdx.app.postRunnable(() -> { Response response = handler.handleMessage(line); - if (response.type == ResponseType.unknownCommand) { + if(response.type == ResponseType.unknownCommand){ int minDst = 0; Command closest = null; @@ -787,12 +789,12 @@ public class ServerControl extends Module { if(closest != null){ err("Command not found. Did you mean \"" + closest.text + "\"?"); - }else { + }else{ err("Invalid command. Type 'help' for help."); } - }else if (response.type == ResponseType.fewArguments) { + }else if(response.type == ResponseType.fewArguments){ err("Too few command arguments. Usage: " + response.command.text + " " + response.command.paramText); - }else if (response.type == ResponseType.manyArguments) { + }else if(response.type == ResponseType.manyArguments){ err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText); } }); @@ -800,9 +802,9 @@ public class ServerControl extends Module { } private void host(){ - try { + try{ Net.host(port); - }catch (IOException e){ + }catch(IOException e){ Log.err(e); state.set(State.menu); } diff --git a/server/src/io/anuke/mindustry/server/ServerLauncher.java b/server/src/io/anuke/mindustry/server/ServerLauncher.java index 4a8c07ba20..dbc25ea35b 100644 --- a/server/src/io/anuke/mindustry/server/ServerLauncher.java +++ b/server/src/io/anuke/mindustry/server/ServerLauncher.java @@ -20,6 +20,37 @@ import java.io.File; public class ServerLauncher extends HeadlessApplication{ ObjectMap prefmap; + public ServerLauncher(ApplicationListener listener, HeadlessApplicationConfiguration config){ + super(listener, config); + + //don't do anything at all for GDX logging: don't want controller info and such + Gdx.app.setApplicationLogger(new ApplicationLogger(){ + @Override + public void log(String tag, String message){ + } + + @Override + public void log(String tag, String message, Throwable exception){ + } + + @Override + public void error(String tag, String message){ + } + + @Override + public void error(String tag, String message, Throwable exception){ + } + + @Override + public void debug(String tag, String message){ + } + + @Override + public void debug(String tag, String message, Throwable exception){ + } + }); + } + public static void main(String[] args){ Net.setClientProvider(new KryoClient()); @@ -33,7 +64,7 @@ public class ServerLauncher extends HeadlessApplication{ //find and handle uncaught exceptions in libGDX thread for(Thread thread : Thread.getAllStackTraces().keySet()){ if(thread.getName().equals("HeadlessApplication")){ - thread.setUncaughtExceptionHandler((t, throwable) ->{ + thread.setUncaughtExceptionHandler((t, throwable) -> { throwable.printStackTrace(); System.exit(-1); }); @@ -42,22 +73,8 @@ public class ServerLauncher extends HeadlessApplication{ } } - public ServerLauncher(ApplicationListener listener, HeadlessApplicationConfiguration config) { - super(listener, config); - - //don't do anything at all for GDX logging: don't want controller info and such - Gdx.app.setApplicationLogger(new ApplicationLogger() { - @Override public void log(String tag, String message) { } - @Override public void log(String tag, String message, Throwable exception) { } - @Override public void error(String tag, String message) { } - @Override public void error(String tag, String message, Throwable exception) { } - @Override public void debug(String tag, String message) { } - @Override public void debug(String tag, String message, Throwable exception) { } - }); - } - @Override - public Preferences getPreferences(String name) { + public Preferences getPreferences(String name){ String prefsDirectory = OS.getAppDataDirectoryString("Mindustry"); if(prefmap == null){