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.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Element; import de.ailis.wlandsuite.io.SeekableInputStream; import de.ailis.wlandsuite.io.SeekableOutputStream; import de.ailis.wlandsuite.utils.StringUtils; import de.ailis.wlandsuite.utils.XmlUtils; /** * The check action defines a skill/check/attribute/... check. * * @author Klaus Reimer (k@ailis.de) * @version $Revision$ */ public class CheckAction implements Action { /** The logger */ private static final Log log = LogFactory.getLog(CheckAction.class); /** If the square is passable even without a successful check */ private boolean passable; /** If auto check should be used */ private boolean autoCheck; /** If all party members are checked or only the first viable character */ private boolean party; /** If damage should be applied to all members when check fails */ private boolean damageAll; /** If all members must pass the check to succeed */ private boolean passAll; /** Unknown bit in check */ private boolean unknown1; /** Bypass armor when calculating damage */ private boolean bypassArmor; /** The message to display when entering the square */ private int startMessage; /** The message to display if the check passed */ private int passMessage; /** The message to display if the check failed */ private int failMessage; /** * The new action class to set when the check passed (255 means setting no * new action class) */ private int passNewActionClass; /** * The new action to set when the check passed (255 means setting no new * action) */ private int passNewAction; /** * The new action class to set when the check failed (255 means setting no * new action class) */ private int failNewActionClass; /** * The new action to set when the check failed (255 means setting no new * action) */ private int failNewAction; /** If the modifier is a fixed value instead of a random dice role */ private boolean fixedModifier; /** The modifier target */ private int modifierTarget; /** The modifier */ private int modifier; /** The checks */ private List<Check> checks = new ArrayList<Check>(); /** * Creates and returns a new Check Action by reading its data from the * specified stream. * * @param stream * The input stream * @return The new Check Action * @throws IOException * When file operation fails. */ public static CheckAction read(final SeekableInputStream stream) throws IOException { CheckAction action; Check check; int flags, b, b1, b2; boolean checkBased; action = new CheckAction(); flags = stream.readByte(); action.passable = (flags & 128) == 128; action.autoCheck = (flags & 64) == 64; action.party = (flags & 32) == 32; action.damageAll = (flags & 16) == 16; checkBased = (flags & 8) == 8; action.passAll = (flags & 4) == 4; action.unknown1 = (flags & 2) == 2; action.bypassArmor = (flags & 1) == 1; action.startMessage = stream.readByte(); action.passMessage = stream.readByte(); action.failMessage = stream.readByte(); action.passNewActionClass = stream.readByte(); action.passNewAction = stream.readByte(); action.failNewActionClass = stream.readByte(); action.failNewAction = stream.readByte(); b1 = stream.readByte(); action.fixedModifier = (b1 & 128) == 128; action.modifierTarget = b1 & 127; b2 = stream.readByte(); action.modifier = (b2 & 127) * (((b2 & 128) == 128) ? -1 : 1); while ((check = Check.read(stream)) != null) { action.checks.add(check); } // Read replacement data if present if (checkBased) { for (final Check c : action.checks) { c.readReplacement(stream); } } // Bugfix for Safe-check on map 3 of game1 if (flags == 64 && action.startMessage == 31 && action.passMessage == 32 && action.failMessage == 0 && action.passNewActionClass == 2 && action.passNewAction == 35 && action.failNewActionClass == 2 && action.failNewAction == 35 && action.modifierTarget == 0 && action.modifier == 0 && !action.fixedModifier && action.checks.size() > 2 && action.checks.get(2).getType() == Check.TYPE_UNKNOWN6) { log.info("Patching safe-check (5) on map 3"); action.checks.remove(3); action.checks.remove(2); } // Bugfix for Safe-check on map 4 of game1 if (flags == 228 && action.startMessage == 65 && action.passMessage == 99 && action.failMessage == 0 && action.passNewActionClass == 8 && action.passNewAction == 5 && action.failNewActionClass == 255 && action.failNewAction == 0 && action.modifierTarget == 0 && action.modifier == 4 && !action.fixedModifier && action.checks.size() > 2 && action.checks.get(2).getType() == Check.TYPE_UNKNOWN7) { log.info("Patching safe-check (20) on map 4"); final List<Check> newChecks = new ArrayList<Check>(); check = new Check(); check.setType(b2 >> 5); check.setDifficulty(b2 & 31); check.setValue((action.checks.get(0).getType() << 5) | action.checks.get(0).getDifficulty()); newChecks.add(check); check = new Check(); b = action.checks.get(0).getValue(); check.setType(b >> 5); check.setDifficulty(b & 31); check.setValue((action.checks.get(1).getType() << 5) | action.checks.get(1).getDifficulty()); newChecks.add(check); action.checks = newChecks; action.modifier = 0; action.failNewAction = 0xff; } // Bugfix for Barrier-check on map 7 of game2 if (flags == 0 && action.startMessage == 36 && action.passMessage == 0 && action.failMessage == 0 && action.passNewActionClass == 255 && action.passNewAction == 255 && action.failNewActionClass == 255 && action.failNewAction == 255 && action.modifierTarget == 0 && action.modifier == 0 && !action.fixedModifier && action.checks.size() > 2 && action.checks.get(2).getType() == Check.TYPE_UNKNOWN4) { log.info("Patching barrier-check (15) on map 4"); action.checks.clear(); action.checks.add(new Check()); } return action; } /** * Creates and returns a Check Action by reading its data from XML. * * @param element * The XML element * @return The Check Action */ public static CheckAction read(final Element element) { CheckAction action; action = new CheckAction(); action.passable = Boolean.parseBoolean(element.attributeValue("passable", "false")); action.autoCheck = Boolean.parseBoolean(element.attributeValue("autoCheck", "false")); action.party = Boolean.parseBoolean(element.attributeValue("party", "false")); action.damageAll = Boolean.parseBoolean(element.attributeValue("damageAll", "false")); action.passAll = Boolean.parseBoolean(element.attributeValue("passAll", "false")); action.unknown1 = Boolean.parseBoolean(element.attributeValue("unknown1", "false")); action.bypassArmor = Boolean.parseBoolean(element.attributeValue("bypassArmor", "false")); action.startMessage = StringUtils.toInt(element.attributeValue("startMessage", "0")); action.passMessage = StringUtils.toInt(element.attributeValue("passMessage", "0")); action.failMessage = StringUtils.toInt(element.attributeValue("failMessage", "0")); action.passNewActionClass = StringUtils.toInt(element.attributeValue("passNewActionClass", "255")); action.passNewAction = StringUtils.toInt(element.attributeValue("passNewAction", "255")); action.failNewActionClass = StringUtils.toInt(element.attributeValue("failNewActionClass", "255")); action.failNewAction = StringUtils.toInt(element.attributeValue("failNewAction", "255")); action.fixedModifier = Boolean.parseBoolean(element.attributeValue("fixedModifier", "false")); action.modifierTarget = StringUtils.toInt(element.attributeValue("modifierTarget", "0x1d")); action.modifier = StringUtils.toInt(element.attributeValue("modifier", "0")); // Read the checks for (final Object check : element.elements()) { Element subElement; subElement = (Element) check; action.checks.add(Check.read(subElement)); } // Return the check action return action; } /** * @see de.ailis.wlandsuite.game.parts.Action#toXml(int) */ @Override public Element toXml(final int id) { Element element; element = XmlUtils.createElement("check"); element.addAttribute("id", StringUtils.toHex(id)); if (this.passable) element.addAttribute("passable", "true"); if (this.autoCheck) element.addAttribute("autoCheck", "true"); if (this.party) element.addAttribute("party", "true"); if (this.damageAll) element.addAttribute("damageAll", "true"); if (this.passAll) element.addAttribute("passAll", "true"); if (this.unknown1) element.addAttribute("unknown1", "true"); if (this.bypassArmor) element.addAttribute("bypassArmor", "true"); if (this.startMessage != 0) { element.addAttribute("startMessage", Integer.toString(this.startMessage)); } if (this.passMessage != 0) { element.addAttribute("passMessage", Integer.toString(this.passMessage)); } if (this.failMessage != 0) { element.addAttribute("failMessage", Integer.toString(this.failMessage)); } if (this.passNewActionClass != 255) { element.addAttribute("passNewActionClass", StringUtils.toHex(this.passNewActionClass)); } if (this.passNewAction != 255) { element.addAttribute("passNewAction", StringUtils.toHex(this.passNewAction)); } if (this.failNewActionClass != 255) { element.addAttribute("failNewActionClass", StringUtils.toHex(this.failNewActionClass)); } if (this.failNewAction != 255) { element.addAttribute("failNewAction", StringUtils.toHex(this.failNewAction)); } if (this.fixedModifier) element.addAttribute("fixedModifier", "true"); if (this.modifierTarget != 0x1d) { element.addAttribute("modifierTarget", StringUtils.toHex(this.modifierTarget)); } if (this.modifier != 0) { element.addAttribute("modifier", Integer.toString(this.modifier)); } for (final Check check : this.checks) { element.add(check.toXml()); } return element; } /** * @throws IOException * When file operation fails. * @see de.ailis.wlandsuite.game.parts.Action#write(de.ailis.wlandsuite.io.SeekableOutputStream, * de.ailis.wlandsuite.game.parts.SpecialActionTable) */ @Override public void write(final SeekableOutputStream stream, final SpecialActionTable specialActionTable) throws IOException { int b; boolean checkBased; checkBased = false; for (final Check check : this.checks) { if (check.getNewActionClass() != -1) { checkBased = true; break; } } b = this.passable ? 128 : 0; b |= this.autoCheck ? 64 : 0; b |= this.party ? 32 : 0; b |= this.damageAll ? 16 : 0; b |= checkBased ? 8 : 0; b |= this.passAll ? 4 : 0; b |= this.unknown1 ? 2 : 0; b |= this.bypassArmor ? 1 : 0; stream.write(b); stream.write(this.startMessage); stream.write(this.passMessage); stream.write(this.failMessage); stream.write(this.passNewActionClass); stream.write(this.passNewAction); stream.write(this.failNewActionClass); stream.write(this.failNewAction); b = this.fixedModifier ? 128 : 0; stream.write(b | (this.modifierTarget & 127)); b = this.modifier < 0 ? 128 : 0; stream.write(b | (Math.abs(this.modifier))); for (final Check check : this.checks) { check.write(stream); } stream.write(255); if (checkBased) { for (final Check check : this.checks) { check.writeReplacement(stream); } } } /** * Returns the start message. * * @return The start message */ public int getStartMessage() { return this.startMessage; } /** * Sets the start message. * * @param startMessage * The start message to set */ public void setStartMessage(final int startMessage) { this.startMessage = startMessage; } /** * Returns the new action class to set when the check failes. * * @return The action class */ public int getFailNewActionClass() { return this.failNewActionClass; } /** * Sets the new action class to set when the check failes. * * @param failNewActionClass * The action class to set */ public void setFailNewActionClass(final int failNewActionClass) { this.failNewActionClass = failNewActionClass; } /** * Returns the new action to set when the check failes. * * @return The action */ public int getFailNewAction() { return this.failNewAction; } /** * Sets the new action to set when the check failes. * * @param failNewAction * The action to set */ public void setFailNewAction(final int failNewAction) { this.failNewAction = failNewAction; } /** * Returns the fail message. * * @return The fail message */ public int getFailMessage() { return this.failMessage; } /** * Sets the fail message. * * @param failMessage * The fail message to set */ public void setFailMessage(final int failMessage) { this.failMessage = failMessage; } /** * Returns the new action class to set when the check passes. * * @return The action class */ public int getPassNewActionClass() { return this.passNewActionClass; } /** * Sets the new action class to set when the check passes. * * @param passNewActionClass * The action class to set */ public void setPassNewActionClass(final int passNewActionClass) { this.passNewActionClass = passNewActionClass; } /** * Returns the new action to set when the check passes. * * @return The action */ public int getPassNewAction() { return this.passNewAction; } /** * Sets the new action to set when the check passes. * * @param passNewAction * The action to set */ public void setPassNewAction(final int passNewAction) { this.passNewAction = passNewAction; } /** * Returns the pass message. * * @return The pass message */ public int getPassMessage() { return this.passMessage; } /** * Sets the pass message. * * @param passMessage * The pass message to set */ public void setPassMessage(final int passMessage) { this.passMessage = passMessage; } /** * Adds a new check * * @param check * The check to add */ public void addCheck(final Check check) { this.checks.add(check); } /** * Returns the check with the specified index. * * @param index * The index * @return The check */ public Check getCheck(final int index) { return this.checks.get(index); } /** * Sets a check at a specific index. * * @param index * The index * @param check * The check */ public void setCheck(final int index, final Check check) { this.checks.set(index, check); } /** * Deletes all checks */ public void clearChecks() { this.checks.clear(); } /** * Removes the check at the specified index. * * @param index * The index */ public void removeCheck(final int index) { this.checks.remove(index); } /** * Returns the number of checks. * * @return The number of checks */ public int countChecks() { return this.checks.size(); } /** * Inserts a check at a specific index. * * @param index * The index * @param check * The check */ public void addCheck(final int index, final Check check) { this.checks.add(index, check); } /** * Returns the autoCheck. * * @return The autoCheck */ public boolean isAutoCheck() { return this.autoCheck; } /** * Sets the autoCheck. * * @param autoCheck * The autoCheck to set */ public void setAutoCheck(final boolean autoCheck) { this.autoCheck = autoCheck; } /** * Returns the bypassArmor. * * @return The bypassArmor */ public boolean isBypassArmor() { return this.bypassArmor; } /** * Sets the bypassArmor. * * @param bypassArmor * The bypassArmor to set */ public void setBypassArmor(final boolean bypassArmor) { this.bypassArmor = bypassArmor; } /** * Returns the checks. * * @return The checks */ public List<Check> getChecks() { return this.checks; } /** * Sets the checks. * * @param checks * The checks to set */ public void setChecks(final List<Check> checks) { this.checks = checks; } /** * Returns the damageAll. * * @return The damageAll */ public boolean isDamageAll() { return this.damageAll; } /** * Sets the damageAll. * * @param damageAll * The damageAll to set */ public void setDamageAll(final boolean damageAll) { this.damageAll = damageAll; } /** * Returns the party. * * @return The party */ public boolean isParty() { return this.party; } /** * Sets the party. * * @param party * The party to set */ public void setParty(final boolean party) { this.party = party; } /** * Returns the passable. * * @return The passable */ public boolean isPassable() { return this.passable; } /** * Sets the passable. * * @param passable * The passable to set */ public void setPassable(final boolean passable) { this.passable = passable; } /** * Returns the passAll. * * @return The passAll */ public boolean isPassAll() { return this.passAll; } /** * Sets the passAll. * * @param passAll * The passAll to set */ public void setPassAll(final boolean passAll) { this.passAll = passAll; } /** * Returns the unknown1. * * @return The unknown1 */ public boolean isUnknown1() { return this.unknown1; } /** * Sets the unknown1. * * @param unknown1 * The unknown1 to set */ public void setUnknown1(final boolean unknown1) { this.unknown1 = unknown1; } /** * Returns the fixedModifier. * * @return The fixedModifier */ public boolean isFixedModifier() { return this.fixedModifier; } /** * Sets the fixedModifier. * * @param fixedModifier * The fixedModifier to set */ public void setFixedModifier(final boolean fixedModifier) { this.fixedModifier = fixedModifier; } /** * Returns the modifier. * * @return The modifier */ public int getModifier() { return this.modifier; } /** * Sets the modifier. * * @param modifier * The modifier to set */ public void setModifier(final int modifier) { this.modifier = modifier; } /** * Returns the modifierTarget. * * @return The modifierTarget */ public int getModifierTarget() { return this.modifierTarget; } /** * Sets the modifierTarget. * * @param modifierTarget * The modifierTarget to set */ public void setModifierTarget(final int modifierTarget) { this.modifierTarget = modifierTarget; } }