Java tutorial
/* * $Id$ * Copyright (C) 2006 Klaus Reimer <k@ailis.de> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ package de.ailis.wlandsuite.game.parts; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import org.dom4j.Element; import de.ailis.wlandsuite.common.exceptions.GameException; import de.ailis.wlandsuite.io.SeekableInputStream; import de.ailis.wlandsuite.io.SeekableOutputStream; import de.ailis.wlandsuite.utils.StringUtils; import de.ailis.wlandsuite.utils.XmlUtils; /** * Character data * * @author Klaus Reimer (k@ailis.de) * @version $Revision$ */ public class Char { /** The nationalities */ private static final String[] nationalities = { "US", "Russian", "Mexican", "Indian", "Chinese" }; /** The character name */ private String name; /** The strength */ private int strength; /** The iq */ private int iq; /** The luck */ private int luck; /** The speed */ private int speed; /** The agility */ private int agility; /** The dexterity */ private int dexterity; /** The charisma */ private int charisma; /** The current money */ private int money; /** The gender (0 = male, 1 = female) */ private int gender; /** * The nationality (0 = US, 1 = Russian, 2 = Mexican, 3 = Indian, 4 = * Chinese */ private int nationality; /** The current armor class */ private int ac; /** The maximum constitution */ private int maxCon; /** The current constitution */ private int con; /** The equipped weapon (Index in item list) */ private int weapon; /** The skill points */ private int skillPoints; /** The experience points */ private int experience; /** The character level */ private int level; /** The equipped armor (Index in item list) */ private int armor; /** The last con before character got unconscious */ private int lastCon; /** Bitmap with afflictions */ private int afflictions; /** If character is an NPC */ private boolean npc; /** Unknown */ private int unknown2A; /** Chance of refusing to use an item */ private int itemRefuse; /** Chance of refusing to use a skill */ private int skillRefuse; /** Chance of refusing to use an attribute */ private int attribRefuse; /** Chance of refusing a trade */ private int tradeRefuse; /** Unknown */ private int unknown2F; /** String to print when NPC joins the party */ private int joinString; /** * Willingness to carry out a Use or Trade command. Checked against the * target characters charisma */ private int willingness; /** The rank */ private String rank; /** The skill list */ private Skills skills; /** The item list */ private Items items; /** * Private Constructor */ private Char() { super(); } /** * Creates and returns a new Char object by reading the data from the * specified input stream. * * @param stream * The stream to read the character data from * @return The newly created character * @throws IOException * When file operation fails. */ public static Char read(final SeekableInputStream stream) throws IOException { byte[] tmp; Char character; // Create new character character = new Char(); tmp = new byte[14]; stream.read(tmp); character.name = getString(tmp); character.strength = stream.read(); character.iq = stream.read(); character.luck = stream.read(); character.speed = stream.read(); character.agility = stream.read(); character.dexterity = stream.read(); character.charisma = stream.read(); character.money = stream.readInt3(); character.gender = stream.read(); character.nationality = stream.read(); character.ac = stream.read(); character.maxCon = stream.readWord(); character.con = stream.readWord(); character.weapon = stream.read(); character.skillPoints = stream.read(); character.experience = stream.readInt3(); character.level = stream.read(); character.armor = stream.read(); character.lastCon = stream.readWord(); character.afflictions = stream.read(); character.npc = stream.read() == 1; character.unknown2A = stream.read(); character.itemRefuse = stream.read(); character.skillRefuse = stream.read(); character.attribRefuse = stream.read(); character.tradeRefuse = stream.read(); character.unknown2F = stream.read(); character.joinString = stream.read(); character.willingness = stream.read(); tmp = new byte[25]; stream.read(tmp); character.rank = getString(tmp); // Skip unknown bytes which are always 0 stream.skip(53); // Read the skills character.skills = Skills.read(stream); stream.skip(1); // Read the items character.items = Items.read(stream); stream.skip(7); // Return the newly creates character return character; } /** * Converts a null-terminated string into a normal string. * * @param data * The null-terminated data * @return The string */ private static String getString(final byte[] data) { int pos = 0; while (pos < data.length && data[pos] != 0) { pos++; } try { return new String(data, 0, pos, "ASCII"); } catch (final UnsupportedEncodingException e) { // Can't happen return null; } } /** * Creates and returns a new character read from the specified XML element. * * @param element * The XML element to read the charactger from * @return The character */ public static Char read(final Element element) { Char character; // Create new character; character = new Char(); character.name = StringUtils.unescape(element.attributeValue("name"), "ASCII"); character.strength = StringUtils.toInt(element.attributeValue("strength")); character.iq = StringUtils.toInt(element.attributeValue("iq")); character.luck = StringUtils.toInt(element.attributeValue("luck")); character.speed = StringUtils.toInt(element.attributeValue("speed")); character.agility = StringUtils.toInt(element.attributeValue("agility")); character.dexterity = StringUtils.toInt(element.attributeValue("dexterity")); character.charisma = StringUtils.toInt(element.attributeValue("charisma")); character.money = StringUtils.toInt(element.attributeValue("money", "0")); character.gender = element.attributeValue("gender", "male").equals("male") ? 0 : 1; character.nationality = getNationality(element.attributeValue("nationality", "US")); character.ac = StringUtils.toInt(element.attributeValue("ac", "0")); character.maxCon = StringUtils.toInt(element.attributeValue("maxCon")); character.con = StringUtils.toInt(element.attributeValue("con")); character.weapon = StringUtils.toInt(element.attributeValue("weapon", "0")); character.skillPoints = StringUtils.toInt(element.attributeValue("skillPoints", "0")); character.experience = StringUtils.toInt(element.attributeValue("experience", "0")); character.level = StringUtils.toInt(element.attributeValue("level", "1")); character.armor = StringUtils.toInt(element.attributeValue("armor", "0")); character.lastCon = StringUtils.toInt(element.attributeValue("lastCon", "0")); character.afflictions = StringUtils.toInt(element.attributeValue("afflictions", "0")); character.npc = Boolean.parseBoolean(element.attributeValue("npc", "false")); character.unknown2A = StringUtils.toInt(element.attributeValue("unknown2A", "0")); character.itemRefuse = StringUtils.toInt(element.attributeValue("itemRefuse", "0")); character.skillRefuse = StringUtils.toInt(element.attributeValue("skillRefuse", "0")); character.attribRefuse = StringUtils.toInt(element.attributeValue("attribRefuse", "0")); character.tradeRefuse = StringUtils.toInt(element.attributeValue("tradeRefuse", "0")); character.unknown2F = StringUtils.toInt(element.attributeValue("unknown2F", "0")); character.joinString = StringUtils.toInt(element.attributeValue("joinString", "0")); character.willingness = StringUtils.toInt(element.attributeValue("willingness", "0")); character.rank = StringUtils.unescape(element.attributeValue("rank", "Private"), "ASCII"); // Read skills character.skills = Skills.read(element.element("skills")); // Read items character.items = Items.read(element.element("items")); // Return the newly created character return character; } /** * Returns the character as XML. * * @param id * The character id * @return The character as XML */ public Element toXml(final int id) { Element element; element = XmlUtils.createElement("character"); element.addAttribute("id", Integer.toString(id)); element.addAttribute("name", StringUtils.escape(this.name, "ASCII")); element.addAttribute("strength", Integer.toString(this.strength)); element.addAttribute("iq", Integer.toString(this.iq)); element.addAttribute("luck", Integer.toString(this.luck)); element.addAttribute("speed", Integer.toString(this.speed)); element.addAttribute("agility", Integer.toString(this.agility)); element.addAttribute("dexterity", Integer.toString(this.dexterity)); element.addAttribute("charisma", Integer.toString(this.charisma)); element.addAttribute("money", Integer.toString(this.money)); element.addAttribute("gender", this.gender == 0 ? "male" : "female"); element.addAttribute("nationality", getNationality(this.nationality)); element.addAttribute("ac", Integer.toString(this.ac)); element.addAttribute("maxCon", Integer.toString(this.maxCon)); element.addAttribute("con", Integer.toString(this.con)); if (this.weapon != 0) { element.addAttribute("weapon", Integer.toString(this.weapon)); } if (this.skillPoints != 0) { element.addAttribute("skillPoints", Integer.toString(this.skillPoints)); } if (this.experience != 0) { element.addAttribute("experience", Integer.toString(this.experience)); } if (this.level != 1) { element.addAttribute("level", Integer.toString(this.level)); } if (this.armor != 0) { element.addAttribute("armor", Integer.toString(this.armor)); } if (this.lastCon != 0) { element.addAttribute("lastCon", Integer.toString(this.lastCon)); } if (this.afflictions != 0) { element.addAttribute("afflictions", Integer.toString(this.afflictions)); } if (this.npc) { element.addAttribute("npc", "true"); } if (this.unknown2A != 0) { element.addAttribute("unknown2A", StringUtils.toHex(this.unknown2A)); } if (this.itemRefuse != 0) { element.addAttribute("itemRefuse", Integer.toString(this.itemRefuse)); } if (this.skillRefuse != 0) { element.addAttribute("skillRefuse", Integer.toString(this.skillRefuse)); } if (this.attribRefuse != 0) { element.addAttribute("attribRefuse", Integer.toString(this.attribRefuse)); } if (this.tradeRefuse != 0) { element.addAttribute("tradeRefuse", Integer.toString(this.tradeRefuse)); } if (this.unknown2F != 0) { element.addAttribute("unknown2F", StringUtils.toHex(this.unknown2F)); } if (this.joinString != 0) { element.addAttribute("joinString", Integer.toString(this.joinString)); } if (this.willingness != 0) { element.addAttribute("willingness", Integer.toString(this.willingness)); } if (!this.rank.equals("Private")) { element.addAttribute("rank", StringUtils.escape(this.rank, "ASCII")); } // Add the skills element.add(this.skills.toXml()); // Add the items element.add(this.items.toXml()); return element; } /** * Writes the character to the specified stream. * * @param stream * The stream to write the character to * @throws IOException * When file operation fails. */ public void write(final SeekableOutputStream stream) throws IOException { stream.write(getBytes(this.name, 14)); stream.write(this.strength); stream.write(this.iq); stream.write(this.luck); stream.write(this.speed); stream.write(this.agility); stream.write(this.dexterity); stream.write(this.charisma); stream.writeInt3(this.money); stream.write(this.gender); stream.write(this.nationality); stream.write(this.ac); stream.writeWord(this.maxCon); stream.writeWord(this.con); stream.write(this.weapon); stream.write(this.skillPoints); stream.writeInt3(this.experience); stream.write(this.level); stream.write(this.armor); stream.writeWord(this.lastCon); stream.write(this.afflictions); stream.write(this.npc ? 1 : 0); stream.write(this.unknown2A); stream.write(this.itemRefuse); stream.write(this.skillRefuse); stream.write(this.attribRefuse); stream.write(this.tradeRefuse); stream.write(this.unknown2F); stream.write(this.joinString); stream.write(this.willingness); stream.write(getBytes(this.rank, 25)); for (int i = 0; i < 53; i++) { stream.write(0); } // Write the skills this.skills.write(stream); stream.write(0); // Write the items this.items.write(stream); for (int i = 0; i < 7; i++) { stream.write(0); } } /** * Converts a string to null-terminated bytes array with a specific length. * * @param string * The string * @param length * The length of the byte array * @return The byte array * @throws IOException * When file operation fails. */ private byte[] getBytes(final String string, final int length) throws IOException { ByteArrayOutputStream stream; stream = new ByteArrayOutputStream(); stream.write(string.getBytes("ASCII")); if (stream.size() > length) { throw new GameException("String is longer than " + length + " bytes: " + string); } for (int i = stream.size(); i < length; i++) { stream.write(0); } return stream.toByteArray(); } /** * Returns the ac. * * @return The ac */ public int getAc() { return this.ac; } /** * Sets the ac. * * @param ac * The ac to set */ public void setAc(final int ac) { this.ac = ac; } /** * Returns the afflictions. * * @return The afflictions */ public int getAfflictions() { return this.afflictions; } /** * Sets the afflictions. * * @param afflictions * The afflictions to set */ public void setAfflictions(final int afflictions) { this.afflictions = afflictions; } /** * Returns the agility. * * @return The agility */ public int getAgility() { return this.agility; } /** * Sets the agility. * * @param agility * The agility to set */ public void setAgility(final int agility) { this.agility = agility; } /** * Returns the armor. * * @return The armor */ public int getArmor() { return this.armor; } /** * Sets the armor. * * @param armor * The armor to set */ public void setArmor(final int armor) { this.armor = armor; } /** * Returns the attribRefuse. * * @return The attribRefuse */ public int getAttribRefuse() { return this.attribRefuse; } /** * Sets the attribRefuse. * * @param attribRefuse * The attribRefuse to set */ public void setAttribRefuse(final int attribRefuse) { this.attribRefuse = attribRefuse; } /** * Returns the charisma. * * @return The charisma */ public int getCharisma() { return this.charisma; } /** * Sets the charisma. * * @param charisma * The charisma to set */ public void setCharisma(final int charisma) { this.charisma = charisma; } /** * Returns the con. * * @return The con */ public int getCon() { return this.con; } /** * Sets the con. * * @param con * The con to set */ public void setCon(final int con) { this.con = con; } /** * Returns the dexterity. * * @return The dexterity */ public int getDexterity() { return this.dexterity; } /** * Sets the dexterity. * * @param dexterity * The dexterity to set */ public void setDexterity(final int dexterity) { this.dexterity = dexterity; } /** * Returns the experience. * * @return The experience */ public int getExperience() { return this.experience; } /** * Sets the experience. * * @param experience * The experience to set */ public void setExperience(final int experience) { this.experience = experience; } /** * Returns the gender. * * @return The gender */ public int getGender() { return this.gender; } /** * Sets the gender. * * @param gender * The gender to set */ public void setGender(final int gender) { this.gender = gender; } /** * Returns the iq. * * @return The iq */ public int getIq() { return this.iq; } /** * Sets the iq. * * @param iq * The iq to set */ public void setIq(final int iq) { this.iq = iq; } /** * Returns the itemRefuse. * * @return The itemRefuse */ public int getItemRefuse() { return this.itemRefuse; } /** * Sets the itemRefuse. * * @param itemRefuse * The itemRefuse to set */ public void setItemRefuse(final int itemRefuse) { this.itemRefuse = itemRefuse; } /** * Returns the items. * * @return The items */ public Items getItems() { return this.items; } /** * Returns the joinString. * * @return The joinString */ public int getJoinString() { return this.joinString; } /** * Sets the joinString. * * @param joinString * The joinString to set */ public void setJoinString(final int joinString) { this.joinString = joinString; } /** * Returns the lastCon. * * @return The lastCon */ public int getLastCon() { return this.lastCon; } /** * Sets the lastCon. * * @param lastCon * The lastCon to set */ public void setLastCon(final int lastCon) { this.lastCon = lastCon; } /** * Returns the level. * * @return The level */ public int getLevel() { return this.level; } /** * Sets the level. * * @param level * The level to set */ public void setLevel(final int level) { this.level = level; } /** * Returns the luck. * * @return The luck */ public int getLuck() { return this.luck; } /** * Sets the luck. * * @param luck * The luck to set */ public void setLuck(final int luck) { this.luck = luck; } /** * Returns the maxCon. * * @return The maxCon */ public int getMaxCon() { return this.maxCon; } /** * Sets the maxCon. * * @param maxCon * The maxCon to set */ public void setMaxCon(final int maxCon) { this.maxCon = maxCon; } /** * Returns the money. * * @return The money */ public int getMoney() { return this.money; } /** * Sets the money. * * @param money * The money to set */ public void setMoney(final int money) { this.money = money; } /** * Returns the name. * * @return The name */ public String getName() { return this.name; } /** * Sets the name. * * @param name * The name to set */ public void setName(final String name) { this.name = name; } /** * Returns the nationality. * * @return The nationality */ public int getNationality() { return this.nationality; } /** * Sets the nationality. * * @param nationality * The nationality to set */ public void setNationality(final int nationality) { this.nationality = nationality; } /** * Returns the npc. * * @return The npc */ public boolean isNpc() { return this.npc; } /** * Sets the npc. * * @param npc * The npc to set */ public void setNpc(final boolean npc) { this.npc = npc; } /** * Returns the rank. * * @return The rank */ public String getRank() { return this.rank; } /** * Sets the rank. * * @param rank * The rank to set */ public void setRank(final String rank) { this.rank = rank; } /** * Returns the skillPoints. * * @return The skillPoints */ public int getSkillPoints() { return this.skillPoints; } /** * Sets the skillPoints. * * @param skillPoints * The skillPoints to set */ public void setSkillPoints(final int skillPoints) { this.skillPoints = skillPoints; } /** * Returns the skillRefuse. * * @return The skillRefuse */ public int getSkillRefuse() { return this.skillRefuse; } /** * Sets the skillRefuse. * * @param skillRefuse * The skillRefuse to set */ public void setSkillRefuse(final int skillRefuse) { this.skillRefuse = skillRefuse; } /** * Returns the skills. * * @return The skills */ public Skills getSkills() { return this.skills; } /** * Returns the speed. * * @return The speed */ public int getSpeed() { return this.speed; } /** * Sets the speed. * * @param speed * The speed to set */ public void setSpeed(final int speed) { this.speed = speed; } /** * Returns the strength. * * @return The strength */ public int getStrength() { return this.strength; } /** * Sets the strength. * * @param strength * The strength to set */ public void setStrength(final int strength) { this.strength = strength; } /** * Returns the tradeRefuse. * * @return The tradeRefuse */ public int getTradeRefuse() { return this.tradeRefuse; } /** * Sets the tradeRefuse. * * @param tradeRefuse * The tradeRefuse to set */ public void setTradeRefuse(final int tradeRefuse) { this.tradeRefuse = tradeRefuse; } /** * Returns the unknown2A. * * @return The unknown2A */ public int getUnknown2A() { return this.unknown2A; } /** * Sets the unknown2A. * * @param unknown2A * The unknown2A to set */ public void setUnknown2A(final int unknown2A) { this.unknown2A = unknown2A; } /** * Returns the unknown2F. * * @return The unknown2F */ public int getUnknown2F() { return this.unknown2F; } /** * Sets the unknown2F. * * @param unknown2F * The unknown2F to set */ public void setUnknown2F(final int unknown2F) { this.unknown2F = unknown2F; } /** * Returns the weapon. * * @return The weapon */ public int getWeapon() { return this.weapon; } /** * Sets the weapon. * * @param weapon * The weapon to set */ public void setWeapon(final int weapon) { this.weapon = weapon; } /** * Returns the willingness. * * @return The willingness */ public int getWillingness() { return this.willingness; } /** * Sets the willingness. * * @param willingness * The willingness to set */ public void setWillingness(final int willingness) { this.willingness = willingness; } /** * Returns the text represenation of a numeric nationality. * * @param nationality * The numeric nationality * @return The text nationality */ public static String getNationality(final int nationality) { return nationalities[nationality]; } /** * Returns the numeric represenation of a textual nationality. * * @param nationality * The textual nationality * @return The numeric nationality */ public static int getNationality(final String nationality) { for (int i = 0; i < nationalities.length; i++) { if (nationalities[i].equals(nationality)) { return i; } } throw new GameException("Unknown nationality: " + nationality); } }