public void setTrainers(List<Trainer> trainerData) {
		int traineroffset = romEntry.getValue("TrainerDataTableOffset");
		int traineramount = 47;
		int[] trainerclasslimits = romEntry.arrayEntries
				.get("TrainerDataClassCounts");

		int[] pointers = new int[traineramount + 1];
		for (int i = 1; i <= traineramount; i++) {
			int tPointer = readWord(traineroffset + (i - 1) * 2);
			pointers[i] = calculateOffset(bankOf(traineroffset), tPointer);
		}

		Iterator<Trainer> allTrainers = trainerData.iterator();
		for (int i = 1; i <= traineramount; i++) {
			int offs = pointers[i];
			int limit = trainerclasslimits[i];
			for (int trnum = 0; trnum < limit; trnum++) {
				Trainer tr = allTrainers.next();
				if (tr.trainerclass != i) {
					System.err.println("Trainer mismatch: " + tr.name);
				}
				Iterator<TrainerPokemon> tPokes = tr.pokemon.iterator();
				// Write their pokemon based on poketype
				if (tr.poketype == 0) {
					// Regular trainer
					int fixedLevel = tr.pokemon.get(0).level;
					rom[offs] = (byte) fixedLevel;
					offs++;
					while (tPokes.hasNext()) {
						TrainerPokemon tpk = tPokes.next();
						rom[offs] = (byte) pokeNumToRBYTable[tpk.pokemon.number];
						offs++;
					}
				} else {
					// Special trainer
					rom[offs] = (byte) 0xFF;
					offs++;
					while (tPokes.hasNext()) {
						TrainerPokemon tpk = tPokes.next();
						rom[offs] = (byte) tpk.level;
						rom[offs + 1] = (byte) pokeNumToRBYTable[tpk.pokemon.number];
						offs += 2;
					}
				}
				rom[offs] = 0;
				offs++;
			}
		}

		// Custom Moves AI Table
		// Zero it out entirely.
		rom[romEntry.getValue("ExtraTrainerMovesTableOffset")] = (byte) 0xFF;

		// Champion Rival overrides in Red/Blue
		if (!isYellow()) {
			// hacky relative offset (very likely to work but maybe not always)
			int champRivalJump = romEntry.getValue("GymLeaderMovesTableOffset") - 0x44;
			// nop out this jump
			rom[champRivalJump] = 0x00;
			rom[champRivalJump + 1] = 0x00;
		}

	}