@Override
	public List<Trainer> getTrainers() {
		int baseOffset = romEntry.getValue("TrainerData");
		int amount = romEntry.getValue("TrainerCount");
		int entryLen = romEntry.getValue("TrainerEntrySize");
		List<Trainer> theTrainers = new ArrayList<Trainer>();
		List<String> tcnames = this.getTrainerClassNames();
		for (int i = 1; i < amount; i++) {
			int trOffset = baseOffset + i * entryLen;
			Trainer tr = new Trainer();
			tr.offset = trOffset;
			int trainerclass = rom[trOffset + 1] & 0xFF;
			tr.trainerclass = (rom[trOffset + 2] & 0x80) > 0 ? 1 : 0;

			int pokeDataType = rom[trOffset] & 0xFF;
			int numPokes = rom[trOffset + (entryLen - 8)] & 0xFF;
			int pointerToPokes = readPointer(trOffset + (entryLen - 4));
			tr.poketype = pokeDataType;
			tr.name = this.readVariableLengthString(trOffset + 4);
			tr.fullDisplayName = tcnames.get(trainerclass) + " " + tr.name;
			// Pokemon data!
			if (pokeDataType == 0) {
				// blocks of 8 bytes
				for (int poke = 0; poke < numPokes; poke++) {
					TrainerPokemon thisPoke = new TrainerPokemon();
					thisPoke.AILevel = readWord(pointerToPokes + poke * 8);
					thisPoke.level = readWord(pointerToPokes + poke * 8 + 2);
					thisPoke.pokemon = pokes[poke3GIndexToNum(readWord(pointerToPokes
							+ poke * 8 + 4))];
					tr.pokemon.add(thisPoke);
				}
			} else if (pokeDataType == 2) {
				// blocks of 8 bytes
				for (int poke = 0; poke < numPokes; poke++) {
					TrainerPokemon thisPoke = new TrainerPokemon();
					thisPoke.AILevel = readWord(pointerToPokes + poke * 8);
					thisPoke.level = readWord(pointerToPokes + poke * 8 + 2);
					thisPoke.pokemon = pokes[poke3GIndexToNum(readWord(pointerToPokes
							+ poke * 8 + 4))];
					thisPoke.heldItem = readWord(pointerToPokes + poke * 8 + 6);
					tr.pokemon.add(thisPoke);
				}
			} else if (pokeDataType == 1) {
				// blocks of 16 bytes
				for (int poke = 0; poke < numPokes; poke++) {
					TrainerPokemon thisPoke = new TrainerPokemon();
					thisPoke.AILevel = readWord(pointerToPokes + poke * 16);
					thisPoke.level = readWord(pointerToPokes + poke * 16 + 2);
					thisPoke.pokemon = pokes[poke3GIndexToNum(readWord(pointerToPokes
							+ poke * 16 + 4))];
					thisPoke.move1 = readWord(pointerToPokes + poke * 16 + 6);
					thisPoke.move2 = readWord(pointerToPokes + poke * 16 + 8);
					thisPoke.move3 = readWord(pointerToPokes + poke * 16 + 10);
					thisPoke.move4 = readWord(pointerToPokes + poke * 16 + 12);
					tr.pokemon.add(thisPoke);
				}
			} else if (pokeDataType == 3) {
				// blocks of 16 bytes
				for (int poke = 0; poke < numPokes; poke++) {
					TrainerPokemon thisPoke = new TrainerPokemon();
					thisPoke.AILevel = readWord(pointerToPokes + poke * 16);
					thisPoke.level = readWord(pointerToPokes + poke * 16 + 2);
					thisPoke.pokemon = pokes[poke3GIndexToNum(readWord(pointerToPokes
							+ poke * 16 + 4))];
					thisPoke.heldItem = readWord(pointerToPokes + poke * 16 + 6);
					thisPoke.move1 = readWord(pointerToPokes + poke * 16 + 8);
					thisPoke.move2 = readWord(pointerToPokes + poke * 16 + 10);
					thisPoke.move3 = readWord(pointerToPokes + poke * 16 + 12);
					thisPoke.move4 = readWord(pointerToPokes + poke * 16 + 14);
					tr.pokemon.add(thisPoke);
				}
			}
			theTrainers.add(tr);
		}

		if (romEntry.romType == RomType_Ruby
				|| romEntry.romType == RomType_Sapp) {
			trainerTagsRS(theTrainers);
		} else if (romEntry.romType == RomType_Em) {
			trainerTagsE(theTrainers);
		} else {
			trainerTagsFRLG(theTrainers);
		}
		return theTrainers;
	}