/* * Initiative - A role playing utility to track turns * Copyright (C) 2002 Devon D Jones * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * SystemHP.java */ package gmgen.plugin; import pcgen.core.Globals; import pcgen.core.PCStat; import pcgen.core.PlayerCharacter; import pcgen.core.SettingsHandler; /** * Deals with the HP part of the gmgen plugin system */ public class SystemHP { private State state = State.Nothing; private SystemAttribute attribute; private boolean firstround; private int current; private int max; private int subdual; /** * Constructor * @param attribute * @param hpmax * @param current */ public SystemHP(SystemAttribute attribute, int hpmax, int current) { this.attribute = attribute; this.max = hpmax; this.current = current; } /** * Constructor * @param attribute * @param hpmax */ public SystemHP(SystemAttribute attribute, int hpmax) { this(attribute, hpmax, hpmax); } /** * Constructor * @param hpmax */ public SystemHP(int hpmax) { this(new SystemAttribute("Attribute", 10), hpmax, hpmax); } /** * Set Attribute * @param attribute */ public void setAttribute(SystemAttribute attribute) { this.attribute = attribute; } /** * Get attribute * @return attribute */ public SystemAttribute getAttribute() { return attribute; } /** * Set the current HP * @param current */ public void setCurrent(int current) { int currentHP = current; if (currentHP > max) { currentHP = max; } if (currentHP > this.current) { heal(currentHP - this.current); } else if (currentHP < this.current) { damage(this.current - currentHP); } } /** * Get the current HP * @return the current HP */ public int getCurrent() { return current; } /** * Returns true if the damage done is Massive damage under the * d20 Modern system * * @param cbt * @param damage * @return true if the damage done is Massive damage under the * d20 Modern system */ public static boolean isD20ModernMassive(Combatant cbt, int damage) { if (cbt instanceof PcgCombatant) { PcgCombatant pcgcbt = (PcgCombatant) cbt; PlayerCharacter pc = pcgcbt.getPC(); PCStat stat = Globals.getContext().getReferenceContext() .silentlyGetConstructedCDOMObject(PCStat.class, "CON"); if (damage > pc.getTotalStatFor(stat)) { return true; } } else { if (damage > cbt.getHP().getAttribute().getValue()) { return true; } } return false; } /** * Returns true if the damage done is Massive damage under the * d20 DnD system * * @param cbt * @param damage * @return true if the damage done is Massive damage under the * d20 DnD system */ public static boolean isDndMassive(Combatant cbt, int damage) { int damageThreshold = 50; if (SettingsHandler.getGMGenOption("Initiative.Damage.Massive.SizeMod", true)) { if (cbt instanceof PcgCombatant) { PcgCombatant pcgcbt = (PcgCombatant) cbt; PlayerCharacter pc = pcgcbt.getPC(); String size = pc.getDisplay().getSize(); //FIX: This needs to be moved to pcgen's sizeAdjustment.lst if (size.equals("Fine")) { damageThreshold = 10; } if (size.equals("Diminutive")) { damageThreshold = 20; } if (size.equals("Tiny")) { damageThreshold = 30; } if (size.equals("Small")) { damageThreshold = 40; } //Medium 50 if (size.equals("Large")) { damageThreshold = 60; } if (size.equals("Huge")) { damageThreshold = 70; } if (size.equals("Gargantuan")) { damageThreshold = 80; } if (size.equals("Colossal")) { damageThreshold = 90; } } } return damage >= damageThreshold; } /** * Returns true if the damage done is Massive damage under the * the 1/2 of max hitpoints house rule * * @param cbt * @param damage * @return true if the damage done is Massive damage under the * the 1/2 of max hitpoints house rule */ public static boolean isHouseHalfMassive(Combatant cbt, int damage) { SystemHP hp = cbt.getHP(); return damage > hp.getMax(); } /** * Set the max HP * @param hpmax */ public void setMax(int hpmax) { this.max = hpmax; if (max > current) { current = max; } } /** * Get the max HP * @return max HP */ public int getMax() { return max; } /** * Set the state * @param state */ public void setState(State state) { this.state = state; } /** * Get the state * @return state */ public State getState() { return state; } /** * Set the subdual damage * @param subdual */ public void setSubdual(int subdual) { subdualDamage(subdual - getSubdual()); } /** * Get the subdual damage * @return subdual damage */ public int getSubdual() { return subdual; } /** * Apply damage because of the Bleeding state * @return the state */ public State bleed() { if (state == State.Bleeding && !firstround) { damage(1); } return state; } /** * Apply damage * @param damage * @return state */ public State damage(int damage) { if ((current > -1) && ((current - damage) < 0)) { boolean dyingStart = SettingsHandler.getGMGenOption("Initiative.Damage.Dying.Start", true); if (!dyingStart) { firstround = true; } } current -= damage; //TODO: Make it so that we can use static finals from somewhere here // and not "1" or "2" // Should we also set up static constants for "Initiative.Damage.Death" . . . int disabledType = SettingsHandler.getGMGenOption( "Initiative.Damage.Disabled", 1); int disabledLowRange = 0; if (disabledType == 2) { disabledLowRange = -1 * Math.max(0,attribute.getModifier()); } if (current <= 0 && current >= disabledLowRange) { state = State.Disabled; } else if (current < disabledLowRange) { state = State.Bleeding; } //TODO: Make it so that we can use static finals from somewhere here // and not "1" or "2" // Should we also set up static constants for "Initiative.Damage.Death" . . . int deathType = SettingsHandler.getGMGenOption( "Initiative.Damage.Death", 1); if (deathType == 1) { if (current <= -10) { state = State.Dead; current = 0; } } else if (deathType == 2) { if (current <= (-1 * attribute.getValue())) { state = State.Dead; current = 0; } } checkSubdual(); return state; } /** * End status that has a duration, e.g. Dazed * @return state */ public State endDurationedStatus() { if (state == State.Unconsious || state == State.Dazed) { state = State.Nothing; } return state; } /** * End the round */ public void endRound() { firstround = false; } /** * Heal * @param heal * @return the state */ public State heal(int heal) { if (state != State.Dead) { current += heal; subdual -= heal; if (current > max) { current = max; } if (subdual < 0) { subdual = 0; } if (state == State.Bleeding) { state = State.Stable; } if (current > 0) { state = State.Nothing; } checkSubdual(); } return state; } /** * Kill the PC * @return the state */ public State kill() { state = State.Dead; current = 0; return state; } /** * Apply non lethal damage * @param type * @return the state */ public State nonLethalDamage(boolean type) { if (state == State.Nothing) { if (type) { state = State.Unconsious; } else { state = State.Dazed; } } return state; } /** * Raise the PC from the dead * @return the state */ public State raise() { if (state == State.Dead) { state = State.Nothing; current = 1; } return state; } /** * Stabilize a bleeding PC * @return the state */ public State stabilize() { if (state == State.Bleeding) { state = State.Stable; } return state; } /** * Apply subdual damage * @param damage * @return the state */ public State subdualDamage(int damage) { subdual += damage; return checkSubdual(); } private State checkSubdual() { //TODO: Make it so that we can use static finals from somewhere here // and not "1" or "2" // Should we also set up static constants for "Initiative.Damage.Death" . . . int disabledType = SettingsHandler.getGMGenOption( "Initiative.Damage.Disabled", 1); int disabledBonus = 0; if (disabledType == 2) { disabledBonus = Math.max(0,attribute.getModifier()); } if ((state == State.Nothing || state == State.Staggered || state == State.Unconsious) && (subdual > 0)) { if (subdual >= current && subdual <= (current + disabledBonus)) { state = State.Staggered; } else if (subdual > (current + disabledBonus)) { state = State.Unconsious; } } return state; } }