// Path: src/com/dabomstew/pkrandom/pokemon/ItemList.java
// public class ItemList {
// 
//     private boolean[] items;
//     private boolean[] tms;
// 
//     public ItemList(int highestIndex) {
//         items = new boolean[highestIndex + 1];
//         tms = new boolean[highestIndex + 1];
//         for (int i = 1; i <= highestIndex; i++) {
//             items[i] = true;
//         }
//     }
// 
//     public boolean isTM(int index) {
//         if (index < 0 || index >= tms.length) {
//             return false;
//         }
//         return tms[index];
//     }
// 
//     public boolean isAllowed(int index) {
//         if (index < 0 || index >= tms.length) {
//             return false;
//         }
//         return items[index];
//     }
// 
//     public void banSingles(int... indexes) {
//         for (int index : indexes) {
//             items[index] = false;
//         }
//     }
// 
//     public void banRange(int startIndex, int length) {
//         for (int i = 0; i < length; i++) {
//             items[i + startIndex] = false;
//         }
//     }
// 
//     public void tmRange(int startIndex, int length) {
//         for (int i = 0; i < length; i++) {
//             tms[i + startIndex] = true;
//         }
//     }
// 
//     public int randomItem(Random random) {
//         int chosen = 0;
//         while (!items[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public int randomNonTM(Random random) {
//         int chosen = 0;
//         while (!items[chosen] || tms[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public int randomTM(Random random) {
//         int chosen = 0;
//         while (!tms[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public ItemList copy() {
//         ItemList other = new ItemList(items.length - 1);
//         System.arraycopy(items, 0, other.items, 0, items.length);
//         System.arraycopy(tms, 0, other.tms, 0, tms.length);
//         return other;
//     }
// 
// }
// 
// Path: src/com/dabomstew/pkrandom/pokemon/MoveCategory.java
// public enum MoveCategory {
//     PHYSICAL, SPECIAL, STATUS;
// }
// 
// Path: src/com/dabomstew/pkrandom/pokemon/Type.java
// public enum Type {
// 
//     NORMAL, FIGHTING, FLYING, GRASS, WATER, FIRE, ROCK, GROUND, PSYCHIC, BUG, DRAGON, ELECTRIC, GHOST, POISON, ICE, STEEL, DARK, GAS(
//             true), FAIRY(true), WOOD(true), ABNORMAL(true), WIND(true), SOUND(true), LIGHT(true), TRI(true);
// 
//     public boolean isHackOnly;
// 
//     private Type() {
//         this.isHackOnly = false;
//     }
// 
//     private Type(boolean isHackOnly) {
//         this.isHackOnly = isHackOnly;
//     }
// 
//     private static final List<Type> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
//     private static final int SIZE = VALUES.size();
// 
//     public static Type randomType(Random random) {
//         return VALUES.get(random.nextInt(SIZE));
//     }
// 
//     public String camelCase() {
//         return RomFunctions.camelCase(this.toString());
//     }
// 
// }


import java.util.Arrays;
import java.util.List;
import com.dabomstew.pkrandom.pokemon.ItemList;
import com.dabomstew.pkrandom.pokemon.MoveCategory;
import com.dabomstew.pkrandom.pokemon.Trainer;
import com.dabomstew.pkrandom.pokemon.Type;
        tag(trs, "GYM4", 0x1f1, 0x1f2, 0x191, 0x153, 0x125, 0x1E3);
        tag(trs, "GYM5", 0x165, 0x145, 0x10a, 0x14a, 0x154, 0x157, 0x118, 0x11c);
        tag(trs, "GYM6", 0x13a, 0x100, 0x101, 0x117, 0x16f, 0xe8, 0x11b);
        tag(trs, "GYM7", 0x10c, 0x10d, 0x10e, 0x10f, 0x33b, 0x33c);
        tag(trs, "GYM8", 0x158, 0x155, 0x12d, 0x12e, 0x12f, 0x11d, 0x119);

        // Gym Leaders
        tag(trs, 0xf6, "GYM1");
        tag(trs, 0x13b, "GYM2");
        tag(trs, 0x13d, "GYM3"); // Maylene
        tag(trs, 0x13c, "GYM4"); // Wake
        tag(trs, 0x13e, "GYM5"); // Fantina
        tag(trs, 0xfa, "GYM6"); // Byron
        tag(trs, 0x13f, "GYM7"); // Candice
        tag(trs, 0x140, "GYM8"); // Volkner

        // Elite 4
        tag(trs, 0x105, "ELITE1");
        tag(trs, 0x106, "ELITE2");
        tag(trs, 0x107, "ELITE3");
        tag(trs, 0x108, "ELITE4");
        tag(trs, 0x10b, "CHAMPION");

        // Rival battles (8)
        tagRivalConsecutive(trs, "RIVAL1", 0xf8);
        tagRivalConsecutive(trs, "RIVAL2", 0x1d7);
        tagRivalConsecutive(trs, "RIVAL3", 0x1da);
        tagRivalConsecutive(trs, "RIVAL4", 0x1dd);
        // Tag battle is not following ze usual format
        tag(trs, 0x26b, "RIVAL5-0");
// Path: src/com/dabomstew/pkrandom/pokemon/ItemList.java
// public class ItemList {
// 
//     private boolean[] items;
//     private boolean[] tms;
// 
//     public ItemList(int highestIndex) {
//         items = new boolean[highestIndex + 1];
//         tms = new boolean[highestIndex + 1];
//         for (int i = 1; i <= highestIndex; i++) {
//             items[i] = true;
//         }
//     }
// 
//     public boolean isTM(int index) {
//         if (index < 0 || index >= tms.length) {
//             return false;
//         }
//         return tms[index];
//     }
// 
//     public boolean isAllowed(int index) {
//         if (index < 0 || index >= tms.length) {
//             return false;
//         }
//         return items[index];
//     }
// 
//     public void banSingles(int... indexes) {
//         for (int index : indexes) {
//             items[index] = false;
//         }
//     }
// 
//     public void banRange(int startIndex, int length) {
//         for (int i = 0; i < length; i++) {
//             items[i + startIndex] = false;
//         }
//     }
// 
//     public void tmRange(int startIndex, int length) {
//         for (int i = 0; i < length; i++) {
//             tms[i + startIndex] = true;
//         }
//     }
// 
//     public int randomItem(Random random) {
//         int chosen = 0;
//         while (!items[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public int randomNonTM(Random random) {
//         int chosen = 0;
//         while (!items[chosen] || tms[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public int randomTM(Random random) {
//         int chosen = 0;
//         while (!tms[chosen]) {
//             chosen = random.nextInt(items.length);
//         }
//         return chosen;
//     }
// 
//     public ItemList copy() {
//         ItemList other = new ItemList(items.length - 1);
//         System.arraycopy(items, 0, other.items, 0, items.length);
//         System.arraycopy(tms, 0, other.tms, 0, tms.length);
//         return other;
//     }
// 
// }
// 
// Path: src/com/dabomstew/pkrandom/pokemon/MoveCategory.java
// public enum MoveCategory {
//     PHYSICAL, SPECIAL, STATUS;
// }
// 
// Path: src/com/dabomstew/pkrandom/pokemon/Type.java
// public enum Type {
// 
//     NORMAL, FIGHTING, FLYING, GRASS, WATER, FIRE, ROCK, GROUND, PSYCHIC, BUG, DRAGON, ELECTRIC, GHOST, POISON, ICE, STEEL, DARK, GAS(
//             true), FAIRY(true), WOOD(true), ABNORMAL(true), WIND(true), SOUND(true), LIGHT(true), TRI(true);
// 
//     public boolean isHackOnly;
// 
//     private Type() {
//         this.isHackOnly = false;
//     }
// 
//     private Type(boolean isHackOnly) {
//         this.isHackOnly = isHackOnly;
//     }
// 
//     private static final List<Type> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
//     private static final int SIZE = VALUES.size();
// 
//     public static Type randomType(Random random) {
//         return VALUES.get(random.nextInt(SIZE));
//     }
// 
//     public String camelCase() {
//         return RomFunctions.camelCase(this.toString());
//     }
// 
// }


// Path: src/com/dabomstew/pkrandom/constants/Gen4Constants.java
import java.util.Arrays;
import java.util.List;
import com.dabomstew.pkrandom.pokemon.ItemList;
import com.dabomstew.pkrandom.pokemon.MoveCategory;
import com.dabomstew.pkrandom.pokemon.Trainer;
import com.dabomstew.pkrandom.pokemon.Type;

        tag(trs, "GYM4", 0x1f1, 0x1f2, 0x191, 0x153, 0x125, 0x1E3);
        tag(trs, "GYM5", 0x165, 0x145, 0x10a, 0x14a, 0x154, 0x157, 0x118, 0x11c);
        tag(trs, "GYM6", 0x13a, 0x100, 0x101, 0x117, 0x16f, 0xe8, 0x11b);
        tag(trs, "GYM7", 0x10c, 0x10d, 0x10e, 0x10f, 0x33b, 0x33c);
        tag(trs, "GYM8", 0x158, 0x155, 0x12d, 0x12e, 0x12f, 0x11d, 0x119);

        // Gym Leaders
        tag(trs, 0xf6, "GYM1");
        tag(trs, 0x13b, "GYM2");
        tag(trs, 0x13d, "GYM3"); // Maylene
        tag(trs, 0x13c, "GYM4"); // Wake
        tag(trs, 0x13e, "GYM5"); // Fantina
        tag(trs, 0xfa, "GYM6"); // Byron
        tag(trs, 0x13f, "GYM7"); // Candice
        tag(trs, 0x140, "GYM8"); // Volkner

        // Elite 4
        tag(trs, 0x105, "ELITE1");
        tag(trs, 0x106, "ELITE2");
        tag(trs, 0x107, "ELITE3");
        tag(trs, 0x108, "ELITE4");
        tag(trs, 0x10b, "CHAMPION");

        // Rival battles (8)
        tagRivalConsecutive(trs, "RIVAL1", 0xf8);
        tagRivalConsecutive(trs, "RIVAL2", 0x1d7);
        tagRivalConsecutive(trs, "RIVAL3", 0x1da);
        tagRivalConsecutive(trs, "RIVAL4", 0x1dd);
        // Tag battle is not following ze usual format
        tag(trs, 0x26b, "RIVAL5-0");
        tag(trs, 0x26c, "RIVAL5-1");