@Override
	public List<Trainer> getTrainers() {
		List<Trainer> allTrainers = new ArrayList<Trainer>();
		try {
			NARCContents trainers = this.readNARC(romEntry
					.getString("TrainerData"));
			NARCContents trpokes = this.readNARC(romEntry
					.getString("TrainerPokemon"));
			int trainernum = trainers.files.size();
			List<String> tclasses = this.getTrainerClassNames();
			List<String> tnames = this.getTrainerNames();
			for (int i = 1; i < trainernum; i++) {
				byte[] trainer = trainers.files.get(i);
				byte[] trpoke = trpokes.files.get(i);
				Trainer tr = new Trainer();
				tr.poketype = trainer[0] & 0xFF;
				tr.offset = trainer[1] & 0xFF;
				tr.trainerclass = trainer[1] & 0xFF;
				int numPokes = trainer[3] & 0xFF;
				int pokeOffs = 0;
				tr.fullDisplayName = tclasses.get(tr.trainerclass) + " "
						+ tnames.get(i - 1);
				// printBA(trpoke);
				for (int poke = 0; poke < numPokes; poke++) {
					// Structure is
					// AI SB LV LV SP SP FRM FRM
					// (HI HI)
					// (M1 M1 M2 M2 M3 M3 M4 M4)
					// where SB = 0 0 Ab Ab 0 0 Fm Ml
					// Ab Ab = ability number, 0 for random
					// Fm = 1 for forced female
					// Ml = 1 for forced male
					// There's also a trainer flag to force gender, but
					// this allows fixed teams with mixed genders.

					int ailevel = trpoke[pokeOffs] & 0xFF;
					// int secondbyte = trpoke[pokeOffs + 1] & 0xFF;
					int level = readWord(trpoke, pokeOffs + 2);
					int species = readWord(trpoke, pokeOffs + 4);
					// int formnum = readWord(trpoke, pokeOffs + 6);
					TrainerPokemon tpk = new TrainerPokemon();
					tpk.level = level;
					tpk.pokemon = pokes[species];
					tpk.AILevel = ailevel;
					tpk.ability = trpoke[pokeOffs + 1] & 0xFF;
					pokeOffs += 8;
					if (tr.poketype >= 2) {
						int heldItem = readWord(trpoke, pokeOffs);
						tpk.heldItem = heldItem;
						pokeOffs += 2;
					}
					if (tr.poketype % 2 == 1) {
						int attack1 = readWord(trpoke, pokeOffs);
						int attack2 = readWord(trpoke, pokeOffs + 2);
						int attack3 = readWord(trpoke, pokeOffs + 4);
						int attack4 = readWord(trpoke, pokeOffs + 6);
						tpk.move1 = attack1;
						tpk.move2 = attack2;
						tpk.move3 = attack3;
						tpk.move4 = attack4;
						pokeOffs += 8;
					}
					tr.pokemon.add(tpk);
				}
				allTrainers.add(tr);
			}
			if (romEntry.romType == Type_BW) {
				tagTrainersBW(allTrainers);
			} else {
				if (!romEntry.getString("DriftveilPokemon").isEmpty()) {
					NARCContents driftveil = this.readNARC(romEntry
							.getString("DriftveilPokemon"));
					for (int trno = 0; trno < 2; trno++) {
						Trainer tr = new Trainer();
						tr.poketype = 3;
						tr.offset = 0;
						for (int poke = 0; poke < 3; poke++) {
							byte[] pkmndata = driftveil.files.get(trno * 3
									+ poke + 1);
							TrainerPokemon tpk = new TrainerPokemon();
							tpk.level = 25;
							tpk.pokemon = pokes[readWord(pkmndata, 0)];
							tpk.AILevel = 255;
							tpk.heldItem = readWord(pkmndata, 12);
							tpk.move1 = readWord(pkmndata, 2);
							tpk.move2 = readWord(pkmndata, 2);
							tpk.move3 = readWord(pkmndata, 2);
							tpk.move4 = readWord(pkmndata, 2);
							tr.pokemon.add(tpk);
						}
						allTrainers.add(tr);
					}
				}
				tagTrainersBW2(allTrainers);
			}
		} catch (IOException ex) {
			// change this later
			ex.printStackTrace();
		}
		return allTrainers;
	}