/*
* PokemonSpeciesData.java
*
* Created on May 19, 2007, 4:49 PM
*
* This file is a part of Shoddy Battle.
* Copyright (C) 2007 Colin Fitzpatrick
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* The Free Software Foundation may be visited online at http://www.fsf.org.
*/
package org.pokenet.server.battle;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import org.pokenet.server.battle.mechanics.PokemonType;
import org.pokenet.server.battle.mechanics.moves.MoveList;
import org.pokenet.server.battle.mechanics.moves.MoveSet;
import org.pokenet.server.battle.mechanics.moves.MoveSetData;
import org.simpleframework.xml.ElementArray;
import org.simpleframework.xml.Root;
/**
*
* @author Colin
*/
@Root
public class PokemonSpeciesData {
private TreeSet<String> m_unimplemented = new TreeSet<String>();
private long m_lastModified;
/**
* A cache of movesets for each species where the origin of the move
* has been removed, as this information is not relevant for the purpose
* of validating pokemon. To speed the latter operation up, this cache
* is useful. Call cacheMoveSets() to create this cache.
*/
private TreeSet<?>[] m_movesets = null;
/**
* Database of all pokemon species.
*/
@ElementArray
private PokemonSpecies[] m_database;
/**
* Get the date when the database was last modified.
*/
public long getLastModified() {
return m_lastModified;
}
/**
* Load a database of pokemon species in from a file, and require that
* abilities have been implemented.
*/
public void loadSpeciesDatabase(File file)
throws IOException, FileNotFoundException {
loadSpeciesDatabase(file, true);
}
/**
* Load a database of pokemon species in from a file.
*/
public void loadSpeciesDatabase(File file, boolean requireImplementation)
throws IOException, FileNotFoundException {
m_lastModified = file.lastModified();
FileInputStream input = new FileInputStream(file);
loadSpeciesDatabase(input, requireImplementation);
input.close();
}
/**
* Load a database of pokemon species in from an input stream.
*/
@SuppressWarnings("unused")
public void loadSpeciesDatabase(InputStream input,
boolean requireImplementation) throws IOException {
ObjectInputStream stream = new ObjectInputStream(input);
int size = stream.readInt();
m_unimplemented = new TreeSet<String>();
m_database = new PokemonSpecies[size];
for (int i = 0; i < size; ++i) {
try {
String name = (String)stream.readObject();
try {
PokemonType[] type = (PokemonType[])stream.readObject();
} catch(Exception e) {}
int[] base = (int[])stream.readObject();
int genders = stream.readInt();
String[] ability = (String[])stream.readObject();
m_database[i] = new PokemonSpecies(i, name, base, genders);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new InternalError();
}
}
Iterator<String> i = m_unimplemented.iterator();
while (i.hasNext()) {
String ability = (String)i.next();
System.out.println("Unimplemented intrinsic ability: " + ability);
}
m_unimplemented = null;
}
/**
* Cache the move sets of all of the pokemon.
*/
public void cacheMoveSets(MoveList moveList,
MoveSetData moveSet,
boolean requireImplementation) {
// This function will double as an error catching mechanism for
// unimplemented moves.
TreeSet<String> unimplemented = new TreeSet<String>();
HashSet<String> implemented = new HashSet<String>();
m_movesets = new TreeSet[m_database.length];
for (int i = 0; i < m_database.length; ++i) {
MoveSet set = null;
try {
set = moveSet.getMoveSet(i);
} catch (IllegalArgumentException e) { }
if (set == null) {
m_movesets[i] = null;
continue;
}
String[][] moves = set.getMoves();
TreeSet<String> list = new TreeSet<String>();
for (int j = 0; j < moves.length; ++j) {
if (!requireImplementation) {
list.addAll(Arrays.asList(moves[j]));
continue;
}
String[] entries = moves[j];
for (int k = 0; k < entries.length; ++k) {
// We enter these manually rather than using addAll()
// so that we can verify that the moves are actually
// implemented.
String move = entries[k];
if (moveList.getMove(move) != null) {
// It is actually implemented.
list.add(move);
implemented.add(move);
} else {
/**
* Add this to the list of unimplemented moves for the
* sole purpose of calculating the percent that are
* implemented.
*/
if (move != null) {
unimplemented.add(move);
}
/**
* Remove this unimplemented move from this list so
* that the server doesn't send the client a list of
* moves containing unimplemented entries.
*/
entries[k] = null;
}
}
}
m_movesets[i] = list;
}
// Print out moves that were unimplemented.
Iterator<String> i = unimplemented.iterator();
while (i.hasNext()) {
String str = (String)i.next();
System.out.println("Unimplemented move: " + str);
}
if (unimplemented.size() != 0) {
System.out.println("There are "
+ String.valueOf(unimplemented.size())
+ " unimplemented moves.");
double total = (double)(implemented.size() + unimplemented.size());
double perc = ((double)implemented.size() / total) * 100.0;
System.out.println("The move library is "
+ String.valueOf(Math.round(perc))
+ "% implemented.");
}
}
/**
* Return whether an ability is implemented.
*/
public boolean isAbilityImplemented(String ability) {
if (ability == null) {
return false;
}
return !m_unimplemented.contains(ability);
}
/**
* Return whether a pokemon can have a particular ability.
*/
public boolean canUseAbility(String name, String ability) {
if (ability == null) {
return false;
}
String [] possibleAbilities =
getPokemonByName(name).getAbilities();
if(possibleAbilities == null)
return false;
for(int i = 0; i < possibleAbilities.length; i++) {
if(possibleAbilities[i].equalsIgnoreCase(ability))
return true;
}
return false;
}
/**
* Return an array of the names of the possible abilities a given pokemon
* can have. Note that this will return unimplemented abilities as well
* as implemented ones.
*/
public String[] getAbilityNames(String name) {
return getPossibleAbilities(name);
}
/**
* Return a TreeSet of possible abilities. This only includes abilities
* that are actually implemented.
*/
public String[] getPossibleAbilities(String name) {
return getPokemonByName(name).getAbilities();
}
/**
* Get the species database.
*/
public PokemonSpecies[] getSpecies() {
return m_database;
}
/**
* Get a single species.
*/
public PokemonSpecies getSpecies(int i) throws PokemonException {
if(i < 0)
return null;
if (i >= m_database.length)
return null;
return m_database[i];
}
/**
* Get the whole list of species names.
* Note: this call is *expensive*.
*/
public String[] getSpeciesNames() {
String[] names = new String[m_database.length];
for (int i = 0; i < names.length; ++i) {
names[i] = m_database[i].m_name;
}
return names;
}
/**
* Return the number of species.
*/
public int getSpeciesCount() {
return m_database.length;
}
/**
* Find a pokemon by name.
*/
public PokemonSpecies getPokemonByName(String name) {
for (int i = 0; i < m_database.length; ++i) {
if (m_database[i] != null && m_database[i].getName() != null &&
m_database[i].getName().equalsIgnoreCase(name)) {
return m_database[i];
}
}
return null;
}
/**
* Return whether this species can learn a particular move.
*/
public boolean canLearn(PokemonSpecies species, String move) {
try {
String [] moves = species.getStarterMoves();
for(int i = 0; i < moves.length; i++) {
if(moves[i] != null && moves[i].equalsIgnoreCase(move))
return true;
}
if(species.getLevelMoves().containsValue(move))
return true;
moves = species.getTMMoves();
for(int i = 0; i < moves.length; i++) {
if(moves[i] != null && moves[i].equalsIgnoreCase(move))
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}