diff --git a/README.md b/README.md index 1e47535..0d5e5c0 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,6 @@ El APK se generará en: `app/build/outputs/apk/release/app-release.apk` adb install -r app/build/outputs/apk/release/app-release.apk ``` -## Pipeline CI/CD - -El proyecto incluye pipeline automático para Gitea que compila releases al crear tags: - -```bash -git tag v1.0.0 -git push origin v1.0.0 -``` - -- **Trigger**: Tags con formato `v*` -- **JDK**: 21 -- **Android SDK**: API 34, build-tools 34.0.0 -- **Salida**: APK en artifacts - ## Estructura del Proyecto ``` @@ -69,19 +55,19 @@ Helldivers/ ├── settings.gradle ├── gradle.properties ├── gradlew / gradlew.bat -└── .gitea/workflows/android.yml # Pipeline CI/CD +└── .gitea/workflows/android.yml ``` ## Configuración Técnica -|属性|Valor| +| Atributo | Valor | |---|---| -|minSdk|18 (Android 4.3)| -|targetSdk|21 (Android 5.0)| -|compileSdk|34| -|Java|21 con desugaring| -|AGP|8.3.0| -|Resolución|720x1280 xhdpi (landscape)| +| minSdk | 18 (Android 4.3) | +| targetSdk | 21 (Android 5.0) | +| compileSdk | 34 | +| Java | 21 con desugaring | +| AGP | 8.3.0 | +| Resolución | 720x1280 xhdpi (landscape) | ## Contribución diff --git a/app/src/main/java/com/helldivers/app/ActivityGame.java b/app/src/main/java/com/helldivers/app/ActivityGame.java index faeb2ed..9a055c0 100644 --- a/app/src/main/java/com/helldivers/app/ActivityGame.java +++ b/app/src/main/java/com/helldivers/app/ActivityGame.java @@ -3,103 +3,188 @@ package com.helldivers.app; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; -import android.widget.Button; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class ActivityGame extends AppCompatActivity { - private static final String[] ARROWS = new String[]{"\u2191", "\u2193", "\u2190", "\u2192"}; private static final int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3; - - private static final int[][] STRATAGEMS = new int[][]{ - new int[]{UP, DOWN, RIGHT, LEFT, UP}, - new int[]{DOWN, DOWN, UP, RIGHT}, - new int[]{UP, DOWN, RIGHT, UP}, - new int[]{RIGHT, UP, UP, DOWN}, - new int[]{DOWN, UP, LEFT, DOWN, UP, RIGHT, DOWN, UP}, - new int[]{DOWN, UP, DOWN, UP}, + + private static final int[][] STRATAGEMS = { + // Support Weapons (0-30) new int[]{DOWN, LEFT, DOWN, UP, RIGHT}, - new int[]{DOWN, LEFT, RIGHT, UP, DOWN}, - new int[]{DOWN, LEFT, DOWN, UP, UP, LEFT}, new int[]{DOWN, DOWN, LEFT, UP, RIGHT}, + new int[]{DOWN, LEFT, DOWN, UP, UP, LEFT}, + new int[]{DOWN, LEFT, DOWN, UP, LEFT}, + new int[]{DOWN, LEFT, RIGHT, UP, DOWN}, new int[]{DOWN, LEFT, RIGHT, RIGHT, LEFT}, + new int[]{DOWN, LEFT, UP, LEFT, DOWN}, new int[]{DOWN, LEFT, UP, DOWN, UP}, + new int[]{DOWN, LEFT, UP, DOWN, DOWN}, new int[]{DOWN, LEFT, DOWN, UP, UP, RIGHT}, - new int[]{DOWN, RIGHT, DOWN, UP, LEFT, RIGHT}, + new int[]{DOWN, RIGHT, DOWN, UP, LEFT, LEFT}, + new int[]{DOWN, DOWN, UP, LEFT, RIGHT}, + new int[]{UP, UP, LEFT, RIGHT}, + new int[]{DOWN, LEFT, UP, DOWN, RIGHT}, new int[]{DOWN, DOWN, UP, DOWN, DOWN}, + new int[]{RIGHT, DOWN, UP, LEFT, RIGHT}, + new int[]{DOWN, DOWN, UP, DOWN, RIGHT}, + new int[]{DOWN, LEFT, RIGHT, LEFT, UP}, + new int[]{DOWN, LEFT, UP, LEFT, RIGHT}, + new int[]{RIGHT, DOWN, LEFT, UP, RIGHT}, + new int[]{DOWN, DOWN, LEFT, UP, LEFT}, + new int[]{DOWN, DOWN, LEFT, UP, DOWN}, + new int[]{RIGHT, UP, LEFT, RIGHT}, + new int[]{DOWN, LEFT, RIGHT, RIGHT, DOWN}, + new int[]{DOWN, LEFT, UP, DOWN, LEFT}, + new int[]{DOWN, LEFT, UP, LEFT, UP, UP}, + new int[]{UP, RIGHT, DOWN, LEFT, DOWN}, + new int[]{DOWN, DOWN, LEFT, UP, UP, LEFT}, + new int[]{DOWN, LEFT, RIGHT, LEFT, UP, UP}, + new int[]{UP, DOWN, DOWN, UP, UP, DOWN}, + // Orbital Strikes (31-42) + new int[]{RIGHT, RIGHT, UP}, new int[]{RIGHT, DOWN, LEFT, UP, UP}, - new int[]{RIGHT, RIGHT, RIGHT}, + new int[]{RIGHT, RIGHT, DOWN, RIGHT}, new int[]{RIGHT, RIGHT, DOWN, LEFT, RIGHT, DOWN}, + new int[]{RIGHT, RIGHT, RIGHT}, + new int[]{RIGHT, RIGHT, DOWN, UP}, + new int[]{RIGHT, RIGHT, LEFT, DOWN}, new int[]{RIGHT, DOWN, UP, UP, LEFT, DOWN, DOWN}, new int[]{RIGHT, DOWN, RIGHT, DOWN, RIGHT, DOWN}, new int[]{RIGHT, DOWN, UP, RIGHT, DOWN}, - new int[]{RIGHT, UP, DOWN, DOWN, RIGHT}, + new int[]{RIGHT, RIGHT, DOWN, LEFT, RIGHT, UP}, + new int[]{UP, DOWN, DOWN, UP, RIGHT}, + // Eagle Strikes (43-49) new int[]{UP, RIGHT, RIGHT}, new int[]{UP, RIGHT, DOWN, RIGHT}, new int[]{UP, RIGHT, DOWN, DOWN, RIGHT}, - new int[]{UP, RIGHT, DOWN, UP}, - new int[]{DOWN, UP, UP, DOWN, UP}, + new int[]{UP, RIGHT, UP, DOWN}, new int[]{UP, RIGHT, DOWN, UP}, new int[]{UP, RIGHT, UP, LEFT}, new int[]{UP, RIGHT, DOWN, DOWN, DOWN}, - new int[]{UP, UP, LEFT, UP, RIGHT}, - new int[]{RIGHT, RIGHT, UP}, - new int[]{RIGHT, RIGHT, DOWN, RIGHT}, - new int[]{RIGHT, RIGHT, LEFT, DOWN}, - new int[]{RIGHT, RIGHT, DOWN, UP}, - new int[]{DOWN, UP, LEFT, RIGHT, RIGHT, LEFT}, - new int[]{DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT}, - new int[]{DOWN, UP, RIGHT, UP, LEFT, RIGHT}, + // Emplacements (50-57) new int[]{DOWN, LEFT, UP, RIGHT}, - new int[]{DOWN, LEFT, DOWN, UP, UP, DOWN}, - new int[]{DOWN, LEFT, UP, LEFT, DOWN}, - new int[]{DOWN, LEFT, DOWN, UP, LEFT}, new int[]{DOWN, LEFT, LEFT, DOWN}, - new int[]{UP, DOWN, LEFT, UP, RIGHT, RIGHT}, - new int[]{DOWN, LEFT, DOWN, DOWN, UP, LEFT}, - new int[]{DOWN, RIGHT, DOWN, UP, LEFT, LEFT}, - new int[]{DOWN, UP, LEFT, RIGHT, LEFT, RIGHT}, - new int[]{DOWN, UP, RIGHT, RIGHT, UP}, - new int[]{DOWN, UP, RIGHT, LEFT}, - new int[]{DOWN, UP, RIGHT, RIGHT, DOWN}, - new int[]{DOWN, UP, LEFT, UP, RIGHT, DOWN}, - new int[]{DOWN, UP, RIGHT, UP, LEFT, UP}, - new int[]{DOWN, UP, RIGHT, RIGHT, LEFT}, - new int[]{DOWN, UP, RIGHT, DOWN, RIGHT} + new int[]{DOWN, LEFT, UP, UP}, + new int[]{DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT}, + new int[]{UP, LEFT, RIGHT, RIGHT, LEFT}, + new int[]{RIGHT, DOWN, LEFT, RIGHT}, + new int[]{DOWN, LEFT, LEFT, RIGHT}, + new int[]{UP, LEFT, RIGHT, RIGHT, RIGHT}, + // Sentries (58-67) + new int[]{UP, RIGHT, RIGHT, UP}, + new int[]{UP, RIGHT, LEFT}, + new int[]{UP, RIGHT, LEFT, UP, LEFT}, + new int[]{UP, RIGHT, RIGHT, LEFT}, + new int[]{UP, RIGHT, RIGHT, LEFT, RIGHT}, + new int[]{UP, RIGHT, UP, LEFT, RIGHT}, + new int[]{UP, RIGHT, UP, LEFT, DOWN}, + new int[]{UP, RIGHT, UP, UP, LEFT}, + new int[]{UP, RIGHT, UP, DOWN}, + new int[]{UP, RIGHT, UP, DOWN, LEFT}, + // Backpacks (68-80) + new int[]{DOWN, LEFT, DOWN, UP, UP, LEFT}, + new int[]{UP, DOWN, UP, LEFT}, + new int[]{DOWN, LEFT, DOWN, DOWN, RIGHT}, + new int[]{LEFT, RIGHT, LEFT, RIGHT}, + new int[]{LEFT, RIGHT, UP, DOWN}, + new int[]{LEFT, RIGHT, RIGHT, LEFT}, + new int[]{LEFT, RIGHT, UP, DOWN, LEFT}, + new int[]{LEFT, RIGHT, UP, RIGHT, RIGHT}, + new int[]{RIGHT, DOWN, UP, UP, UP}, + new int[]{LEFT, RIGHT, UP, DOWN, UP}, + new int[]{LEFT, UP, LEFT, RIGHT}, + new int[]{LEFT, RIGHT, LEFT, UP}, + new int[]{LEFT, RIGHT, LEFT, RIGHT, LEFT}, + // Vehicles (81-84) + new int[]{LEFT, DOWN, RIGHT, UP, LEFT, LEFT, UP}, + new int[]{LEFT, DOWN, RIGHT, UP, LEFT, LEFT, DOWN}, + new int[]{LEFT, DOWN, RIGHT, DOWN, LEFT, LEFT, DOWN}, + new int[]{LEFT, DOWN, RIGHT, DOWN, LEFT, DOWN, UP, DOWN}, + // Mission (85-103) + new int[]{UP, DOWN, LEFT, UP, UP, LEFT, LEFT}, + new int[]{DOWN, DOWN, UP, LEFT, RIGHT}, + new int[]{UP, DOWN, LEFT, UP}, + new int[]{DOWN, LEFT, DOWN, UP, RIGHT, RIGHT}, + new int[]{RIGHT, RIGHT, RIGHT, RIGHT, UP, UP, LEFT, LEFT}, + new int[]{DOWN, UP, LEFT, DOWN, UP, RIGHT, DOWN, LEFT}, + new int[]{LEFT, RIGHT, UP, DOWN, UP}, + new int[]{DOWN, RIGHT, DOWN, RIGHT, DOWN}, + new int[]{RIGHT, UP, UP, LEFT, UP}, + new int[]{UP, UP, LEFT, RIGHT, LEFT}, + new int[]{DOWN, DOWN, LEFT, RIGHT, LEFT}, + new int[]{LEFT, RIGHT, UP, DOWN, LEFT, LEFT, UP}, + new int[]{LEFT, DOWN, UP, DOWN}, + // Other + new int[]{RIGHT, RIGHT, DOWN, DOWN, UP} }; - private static final String[] NAMES = new String[]{ - "Reforzamiento", "Reabastecimiento", "Baliza SOS", "Artilleria", "Bomba Infernal", - "Bandera", "Ametralladora", "Rifle material", "Leal", "Antitanque", - "Rifle retroceso", "Echador llama", "Canon auto", "Canon riel", "Lanza", - "Bombardeo", "Ataque aereo", "HE 120mm", "HE 380mm", "Aluvion", - "Laser orbital", "Riel orbital", "Carrera", "Ataque", "Racimo", - "Napalm", "Salto", "Humo", "Cohetes", "Bomba 500kg", - "Rearme", "Precision", "Gas", "EMS", "Humo2", - "HMG", "Escudo", "Tesla", "Minas", "Suministros", - "Granadas", "Laser", "Incendiarias", "Rover", "Balistico", - "Arco", "Escudo2", "Centinela1", "Centinela2", "Centinela3", - "Guardian", "Centinela4", "Centinela5", "Centinela6", "Centinela7" + private static final String[] NAMES = { + "Machine Gun", "EAT", "Stalwart", "Laser Cannon", "Anti-Materiel Rifle", "Recoilless Rifle", + "Grenade Launcher", "Flamethrower", "Heavy Machine Gun", "Autocannon", "Arc Thrower", + "Quasar Cannon", "Airburst Rocket", "Commando", "Spear", "Railgun", "W.A.S.P.", + "Breaching Hammer", "Epoch", "Speargun", "Expendable Napalm", "Leveller", "De-Escalator", + "Defoliation", "Sterilizer", "Belt-Fed GL", "Solo Silo", "Cremator", "Maxigun", + "C4 Pack", "One True Flag", + "Orbital Precision", "Orbital Gatling", "Orbital Gas", "Orbital 120mm", "Orbital Airburst", + "Orbital Smoke", "Orbital EMS", "Orbital 380mm", "Orbital Walking", "Orbital Laser", + "Orbital Napalm", "Orbital Railcannon", + "Eagle Strafing", "Eagle Airstrike", "Eagle Cluster", "Eagle Smoke", "Eagle Napalm", + "Eagle Rocket", "Eagle 500kg", + "Anti-Personnel Mines", "Incendiary Mines", "Anti-Tank Mines", "Shield Relay", "HMG Emplacement", + "Grenadier", "Gas Mines", "Anti-Tank Emplacement", + "MG Sentry", "Gatling Sentry", "Autocannon Sentry", "Mortar Sentry", "Rocket Sentry", + "Tesla Tower", "EMS Mortar", "Laser Sentry", "Flame Sentry", "Gas Mortar", + "Supply Pack", "Jump Pack", "Ballistic Shield", "Guard Dog", "Rover", "Shield Generator", + "Directional Shield", "Hot Dog", "Hellbomb", "K-9", "Hover Pack", "Dog Breath", "Warp Pack", + "Patriot Exosuit", "Emancipator", "Fast Recon", "Bastion", + "Reinforce", "Resupply", "SOS Beacon", "Eagle Rearm", "Super Destroyer", + "Hellbomb", "Upload Data", "SSSD", "Super Earth Flag", "Seismic Probe", "Prospecting Drill", + "Dark Fluid", "Tectonic Drill", "Hive Breaker", "Cargo Container", "Reinforcement", "SEAF Artillery", + "Illumination Flare" + }; + + private static final int[] ICONS = new int[]{ + R.drawable.support_1, R.drawable.support_2, R.drawable.support_3, R.drawable.support_4, R.drawable.support_5, + R.drawable.support_6, R.drawable.support_7, R.drawable.support_8, R.drawable.support_9, R.drawable.support_10, + R.drawable.class_1, R.drawable.class_2, R.drawable.class_3, R.drawable.class_4, R.drawable.class_5, + R.drawable.offensive_1, R.drawable.offensive_2, R.drawable.offensive_3, R.drawable.offensive_4, R.drawable.offensive_5, + R.drawable.offensive_6, R.drawable.offensive_7, R.drawable.offensive_8, R.drawable.offensive_9, R.drawable.offensive_10, + R.drawable.supply_1, R.drawable.supply_2, R.drawable.supply_3, R.drawable.supply_4, R.drawable.supply_5, + R.drawable.supply_6, R.drawable.supply_7, R.drawable.supply_8, R.drawable.supply_9, R.drawable.supply_10, + R.drawable.supply_11, R.drawable.supply_12, R.drawable.supply_13, R.drawable.supply_14, R.drawable.supply_15, + R.drawable.defensive_1, R.drawable.defensive_2, R.drawable.defensive_3, R.drawable.defensive_4, R.drawable.defensive_5, + R.drawable.defensive_6, R.drawable.defensive_7, R.drawable.defensive_8, R.drawable.defensive_9, R.drawable.defensive_10, + R.drawable.defensive_11 + }; + + private static final int[] ARROW_ICONS = new int[]{ + R.drawable.stepforward, R.drawable.stepforward, R.drawable.stepforward, R.drawable.stepforward }; private SoundManager soundManager; private Handler handler = new Handler(); - private TextView tvStratagemName; private TextView tvCounter; + private ImageView ivStratagemIcon; + private LinearLayout sequenceContainer; private ImageButton btnUp, btnDown, btnLeft, btnRight; - private Button btnVolver; + private android.widget.Button btnVolver; private int[] sequence; private int playerIndex = 0; private int completadas = 0; private boolean esperando = false; private boolean juegoActivo = true; - private String[] ultimosArrows; - private String ultimosArrowsStratagem; + private int currentStratagemIndex = 0; @Override protected void onCreate(Bundle savedInstanceState) { @@ -109,8 +194,9 @@ public class ActivityGame extends AppCompatActivity { try { soundManager = new SoundManager(this); } catch (Exception e) { soundManager = null; } - tvStratagemName = findViewById(R.id.tv_stratagem_name); tvCounter = findViewById(R.id.tv_counter); + ivStratagemIcon = findViewById(R.id.iv_stratagem_icon); + sequenceContainer = findViewById(R.id.sequence_container); btnUp = findViewById(R.id.btn_up); btnDown = findViewById(R.id.btn_down); btnLeft = findViewById(R.id.btn_left); @@ -127,23 +213,62 @@ public class ActivityGame extends AppCompatActivity { nuevaRonda(); } + private int getArrowRotation(int dir) { + switch(dir) { + case UP: return 0; + case DOWN: return 180; + case LEFT: return -90; + case RIGHT: return 90; + default: return 0; + } + } + private void nuevaRonda() { int idx = (int)(Math.random() * STRATAGEMS.length); sequence = STRATAGEMS[idx]; + currentStratagemIndex = idx; playerIndex = 0; juegoActivo = true; - ultimosArrows = new String[sequence.length]; - ultimosArrowsStratagem = NAMES[idx]; - - if (tvStratagemName != null) { - tvStratagemName.setText(ultimosArrowsStratagem); - tvStratagemName.setTextColor(Color.parseColor("#FFD700")); + + if (ivStratagemIcon != null) { + try { + int iconIndex = idx % ICONS.length; + ivStratagemIcon.setImageResource(ICONS[iconIndex]); + } catch (Exception e) { + ivStratagemIcon.setImageResource(R.drawable.stratagemas_icon); + } } + + secuenciaMostrar(); handler.removeCallbacksAndMessages(null); handler.postDelayed(() -> { esperando = true; }, 1200); } + private static final String ARROW_CHARS = "\u2191\u2193\u2190\u2192"; + + private void secuenciaMostrar() { + if (sequenceContainer == null) return; + sequenceContainer.removeAllViews(); + + for (int i = 0; i < sequence.length; i++) { + TextView arrowView = new TextView(this); + int size = (int)(56 * getResources().getDisplayMetrics().density); + int margin = (int)(4 * getResources().getDisplayMetrics().density); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size, size); + params.setMargins(margin, margin, margin, margin); + arrowView.setLayoutParams(params); + + arrowView.setText(String.valueOf(ARROW_CHARS.charAt(sequence[i]))); + arrowView.setTextSize(36); + arrowView.setTextColor(Color.parseColor("#FFD700")); + arrowView.setGravity(Gravity.CENTER); + arrowView.setBackgroundResource(R.drawable.arrow_white); + + sequenceContainer.addView(arrowView); + } + } + private void onInputWithSound(int dir) { if (soundManager != null) { try { soundManager.playTone(dir); } catch (Exception e) {} @@ -157,19 +282,11 @@ public class ActivityGame extends AppCompatActivity { if (dir == sequence[playerIndex]) { playerIndex++; - if (tvStratagemName != null) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < sequence.length; i++) { - if (i < playerIndex) { - sb.append("").append(ultimosArrows[i]).append(" "); - } else { - sb.append(ultimosArrows[i]).append(" "); - } - } - try { - tvStratagemName.setText(android.text.Html.fromHtml(sb.toString())); - } catch (Exception e) { - tvStratagemName.setText(sb.toString().replaceAll("<[^>]*>", "")); + if (sequenceContainer != null && playerIndex <= sequence.length) { + View child = sequenceContainer.getChildAt(playerIndex - 1); + if (child instanceof TextView) { + TextView arrowView = (TextView) child; + arrowView.setTextColor(Color.parseColor("#00FF00")); } } @@ -179,10 +296,6 @@ public class ActivityGame extends AppCompatActivity { } completadas++; if (tvCounter != null) tvCounter.setText(String.valueOf(completadas)); - if (tvStratagemName != null) { - tvStratagemName.setText("OK!"); - tvStratagemName.setTextColor(Color.parseColor("#00FF00")); - } esperando = false; handler.postDelayed(this::nuevaRonda, 1200); } @@ -190,10 +303,6 @@ public class ActivityGame extends AppCompatActivity { if (soundManager != null) { try { soundManager.playFailure(); } catch (Exception e) {} } - if (tvStratagemName != null) { - tvStratagemName.setText("X"); - tvStratagemName.setTextColor(Color.parseColor("#FF0000")); - } juegoActivo = false; handler.postDelayed(this::nuevaRonda, 1500); } diff --git a/app/src/main/res/drawable/arrow_white.xml b/app/src/main/res/drawable/arrow_white.xml new file mode 100644 index 0000000..31503a9 --- /dev/null +++ b/app/src/main/res/drawable/arrow_white.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_game.xml b/app/src/main/res/layout/activity_game.xml index df22a2d..00fd361 100644 --- a/app/src/main/res/layout/activity_game.xml +++ b/app/src/main/res/layout/activity_game.xml @@ -5,17 +5,8 @@ android:background="@drawable/bg_helldivers_gradient"> - + + - + + - + - - - + android:gravity="center_vertical" + android:orientation="horizontal"> - + + - + - + + - - + - + + - + - + - + - + + + + + + + + + + + + + + + + +