/*
* 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
*
* Initiative.java
*
* Created on September 18, 2002, 4:36 PM
*/
package plugin.initiative.gui;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.stream.Collectors;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.NumberFormatter;
import gmgen.GMGenSystem;
import gmgen.gui.FlippingSplitPane;
import gmgen.io.SimpleFileFilter;
import gmgen.plugin.Combatant;
import gmgen.plugin.Event;
import gmgen.plugin.InfoCharacterDetails;
import gmgen.plugin.InitHolder;
import gmgen.plugin.InitHolderList;
import gmgen.plugin.PcgCombatant;
import gmgen.plugin.Spell;
import gmgen.plugin.State;
import gmgen.plugin.SystemHP;
import gmgen.plugin.SystemInitiative;
import gmgen.plugin.dice.Dice;
import gmgen.pluginmgr.messages.CombatantHasBeenUpdatedMessage;
import gmgen.util.LogUtilities;
import pcgen.core.Globals;
import pcgen.core.PCStat;
import pcgen.core.PlayerCharacter;
import pcgen.core.SettingsHandler;
import pcgen.pluginmgr.PCGenMessageHandler;
import pcgen.pluginmgr.PluginManager;
import pcgen.system.LanguageBundle;
import pcgen.system.PCGenSettings;
import pcgen.util.Logging;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import plugin.initiative.AttackModel;
import plugin.initiative.CheckModel;
import plugin.initiative.DiceRollModel;
import plugin.initiative.InitiativePlugin;
import plugin.initiative.PObjectModel;
import plugin.initiative.SaveModel;
import plugin.initiative.SpellModel;
import plugin.initiative.XMLCombatant;
/**
*@author Devon Jones
*/
public class Initiative extends javax.swing.JPanel
{
//** End Dynamic Components **
//** Other Variables **
/** List that contains the list of Combatants. Kept sorted. */
public final InitHolderList initList = new InitHolderList();
private final JButton bCast = new JButton();
private final JButton bOpposedSkill = new JButton();
private javax.swing.JButton bCombatantReRoll;
private final JButton bDamage = new JButton();
private javax.swing.JButton bDelete;
private final JButton bEvent = new JButton();
private final JButton bHeal = new JButton();
private final JButton bKill = new JButton();
private javax.swing.JButton bNextInit;
private final JButton bRaise = new JButton();
private javax.swing.JButton bRoll;
private final JButton bRefresh = new JButton();
private final javax.swing.JButton bDuplicateCombatant = new JButton();
// End of variables declaration
//** Dynamic Components **
private final JButton bSave = new JButton();
private final JButton bStabilize = new JButton();
private final JCheckBox showDead = new JCheckBox();
private final JCheckBox showEvents = new JCheckBox();
private javax.swing.JCheckBoxMenuItem tablePopupCBDuration;
private javax.swing.JCheckBoxMenuItem tablePopupCBHP;
private javax.swing.JCheckBoxMenuItem tablePopupCBHPMax;
private javax.swing.JCheckBoxMenuItem tablePopupCBInitiative;
private javax.swing.JCheckBoxMenuItem tablePopupCBName;
private javax.swing.JCheckBoxMenuItem tablePopupCBNumber;
private javax.swing.JCheckBoxMenuItem tablePopupCBPlayer;
private javax.swing.JCheckBoxMenuItem tablePopupCBPlus;
//** End Copy & Paste Functions **
// Variables declaration - do not modify
private javax.swing.JCheckBoxMenuItem tablePopupCBStatus;
private javax.swing.JCheckBoxMenuItem tablePopupCBType;
private javax.swing.JLabel lCounter;
private javax.swing.JPopupMenu tablePopup;
private FlippingSplitPane jSplitPane1;
private javax.swing.JTabbedPane tpaneInfo;
private javax.swing.JTable combatantTable;
private javax.swing.JTextArea tpCombatInfo;
private javax.swing.JToolBar bottomToolbar;
private List columnList = new ArrayList();
private LogUtilities log;
private int currentCombat = 1;
private int currentInit = -1;
private int round = 0;
private final PCGenMessageHandler messageHandler;
/*
* History:
* March 20, 2003: Cleanup for Version 1.0
*/
/** Creates new form Initiative */
public Initiative()
{
messageHandler = PluginManager.getInstance().getPostbox();
initComponents();
initDynamicComponents();
initPrefs();
initTable();
initLast();
addTableListener();
jSplitPane1.setOneTouchExpandable(true);
}
/**
* Sets the active Initiative to be the passed in value
*
* @param init - The new Active Initiative value
*/
private void setCurrentInit(int init)
{
currentInit = init;
if (currentInit > 0)
{
lCounter.setText(LanguageBundle.getFormattedString("in_plugin_initiative_round", round, init)); //$NON-NLS-1$
}
else
{
lCounter.setText(""); //$NON-NLS-1$
}
refreshTable();
}
/** Sets current situation for some objects as the default locations, as the program exits */
public void setExitPrefs()
{
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME + ".ShowDead",
showDead.isSelected());
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ShowEvents", showEvents.isSelected());
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".DividerLocation", jSplitPane1.getDividerLocation());
}
/**
* Set the log
* @param log
*/
public void setLog(LogUtilities log)
{
this.log = log;
if (tpaneInfo.getTitleAt(0).equals("Combat"))
{
tpaneInfo.remove(0);
}
}
/**
* Looks at each line in the table, and returns an ArrayList of lines that are Selected.
*
*@return An ArrayList of currently selected InitHolders
*/
private List<InitHolder> getSelected()
{
final List<InitHolder> retList = new ArrayList<>();
int j = -1;
for (int i = 0; i < combatantTable.getRowCount(); i++)
{
j++;
InitHolder iH = initList.get(j);
if ((iH.getStatus() == State.Dead) && !showDead.isSelected())
{
i--;
continue;
}
if ((iH instanceof Event) && !showEvents.isSelected())
{
i--;
continue;
}
if (combatantTable.isRowSelected(i))
{
retList.add(iH);
}
}
return retList;
}
/**
* Looks at each line in the table, and returns an ArrayList of lines that are not Selected.
*
*@return An ArrayList of currently selected InitHolders
*/
private List<InitHolder> getUnSelected()
{
final List<InitHolder> retList = new ArrayList<>();
int j = -1;
for (int i = 0; i < combatantTable.getRowCount(); i++)
{
j++;
InitHolder iH = initList.get(j);
if ((iH.getStatus() == State.Dead) && !showDead.isSelected())
{
i--;
continue;
}
if ((iH instanceof Event) && !showEvents.isSelected())
{
i--;
continue;
}
if (!combatantTable.isRowSelected(i))
{
retList.add(iH);
}
}
return retList;
}
/** Calls up the AddCombatant dialog for adding a new combatant */
private void addCombatant()
{
final JDialog dialog =
new AddCombatant(JOptionPane.getFrameForComponent(this), true,
this);
dialog.setVisible(true);
refreshTable();
}
/**
* Add an initiative holder (a combatant)
* @param iH
*/
public void addInitHolder(InitHolder iH)
{
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
if (!initList.isUniqueName(cbt.getName()))
{
cbt.setName(initList.getUniqueName(cbt.getName()));
}
addTab(cbt);
}
initList.add(iH);
}
/**
* Add a new pcg combatant
* @param pc
* @param type
*/
public void addPcgCombatant(PlayerCharacter pc, String type)
{
String name = initList.getUniqueName(pc.getDisplay().getName());
//Changed from != to .equals 10/21/06 thpr
if (!name.equals(pc.getDisplay().getName()))
{
//Means this one is already loaded, so it should be considered a new pc.
pc.setName(name);
//TODO: Is this necessary? Exactly why?
pc.setFileName("");
}
final PcgCombatant pcgcbt = new PcgCombatant(pc, type, messageHandler);
initList.add(pcgcbt);
addTab(pcgcbt);
}
/**
* <p>
* Adds a tab to the {@code tpaneInfo} member. All methods adding
* character tabs to {@code tpaneInfo} should call this method to do
* so, as it provides a standard setup for the text panes and installs
* hyperlink listeners.
* </p>
*
* @param cbt Combatant to add.
*/
void addTab(final Combatant cbt)
{
javax.swing.JTextPane lp = new javax.swing.JTextPane();
lp.setContentType( "text/html" );
InfoCharacterDetails ic = new InfoCharacterDetails(cbt, lp);
tpaneInfo.addTab(cbt.getName(), ic.getScrollPane());
lp.setEditable(false);
lp.addHyperlinkListener(new HyperlinkListener()
{
private final Combatant combatant = cbt;
@Override
public void hyperlinkUpdate(HyperlinkEvent e)
{
hyperLinkSelected(e, combatant);
}
});
}
//** End Table CoreUtility Functions **
//** Preferences Functions **
/** Applys preference dialog selects as new preferences, and implements those selections */
void applyPrefs()
{
//Combat Prefs
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doCombat", true)
&& !bottomToolbar.isAncestorOf(bSave))
{
bottomToolbar.add(bSave);
}
if (!SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doCombat", true)
&& bottomToolbar.isAncestorOf(bSave))
{
bottomToolbar.remove(bSave);
}
//Spell Prefs
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doSpells", true)
&& !bottomToolbar.isAncestorOf(bCast))
{
bottomToolbar.add(bCast);
bottomToolbar.add(bEvent);
}
if (!SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doSpells", true)
&& bottomToolbar.isAncestorOf(bCast))
{
bottomToolbar.remove(bCast);
bottomToolbar.remove(bEvent);
bottomToolbar.add(showEvents);
}
checkAndFixColumns(SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doSpells", true), "Dur");
//Mixed Prefs
checkAndFixColumns(SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doSpells", true)
|| SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true), "Status");
//HP Prefs
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME + ".doHP",
true)
&& !bottomToolbar.isAncestorOf(bDamage))
{
bottomToolbar.add(bDamage);
bottomToolbar.add(bHeal);
bottomToolbar.add(bStabilize);
}
if (!SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doHP", true)
&& bottomToolbar.isAncestorOf(bDamage))
{
bottomToolbar.remove(bDamage);
bottomToolbar.remove(bHeal);
bottomToolbar.remove(bStabilize);
}
checkAndFixColumns(SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doHP", true), "HP");
checkAndFixColumns(SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doHP", true), "HP Max");
checkAndFixColumns(SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".doNumber", true), "#");
//Death Prefs
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true)
&& !bottomToolbar.isAncestorOf(bKill))
{
bottomToolbar.add(bKill);
bottomToolbar.add(showDead);
}
if (!SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true)
&& bottomToolbar.isAncestorOf(bKill))
{
bottomToolbar.remove(bKill);
bottomToolbar.remove(showDead);
}
initTable();
refreshTable();
repaint();
}
/** Calls up the CastSpell dialog, passing in the data for the first selected combatant, if there is one
* sets the name of the spell as requested.
*/
private void castSpell()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
final InitHolder iH = selectedList.remove(0);
castSpell("", iH, null);
return;
}
initList.sort();
refreshTable();
castSpell("", null, null);
}
/**
* <p>Calls up the CastSpell dialog, passing the data for the indicated combatant (which
* may be null), and sets the name to the indicated value. If SpellModel is present,
* it sets the dialog's spell model as well.</p>
*
* @param name The spell's name; may be empty string.
* @param iH {@code InitHolder} instance, may be null
* @param model {@code SpellModel} instance, may be null
*/
private void castSpell(String name, InitHolder iH, SpellModel model)
{
CastSpell dialog;
if (iH == null)
{
dialog =
new CastSpell(JOptionPane.getFrameForComponent(this), true,
this);
}
else
{
dialog =
new CastSpell(JOptionPane.getFrameForComponent(this), true,
this, iH.getPlayer(), iH.getInitiative()
.getCurrentInitiative());
}
if (name != null)
{
dialog.setSpellName(name);
}
if (model != null)
{
dialog.setSpellModel(model);
}
dialog.setVisible(true);
refreshTable();
}
/**
* Check for dead combatants
*/
private void checkDeadTabs()
{
initList.stream().filter(anInitList -> anInitList.getStatus() == State.Dead).forEach(anInitList ->
{
if (showDead.isSelected() && (anInitList instanceof Combatant)
&& (tpaneInfo.indexOfTab(anInitList.getName()) == -1))
{
Combatant cbt = (Combatant) anInitList;
addTab(cbt);
}
else
{
removeTab(anInitList);
}
});
}
/**
* Set the current initiative holder to dead
* @param deadIH
*/
private void combatantDied(InitHolder deadIH)
{
writeToCombatTabWithRound(deadIH.getName() + " (" + deadIH.getPlayer()
+ ") Killed");
for (InitHolder anInitList : initList)
{
String cbtType = "";
if (anInitList instanceof Combatant)
{
Combatant cbt = (Combatant) anInitList;
cbtType = cbt.getCombatantType();
}
if (cbtType.equals("Enemy") && (anInitList.getStatus() != State.Dead))
{
return;
}
}
writeToCombatTabWithRound("Combat finished, all enemies killed");
checkDeadTabs();
}
//** End Functions called by dialogs **
//** Copy & Paste Functions **
/** Damages the selected combatants */
private void damageCombatant()
{
int subdualType =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".Damage.Subdual", PreferencesDamagePanel.DAMAGE_SUBDUAL);
DamageDialog dialog = new DamageDialog(GMGenSystem.inst, true);
dialog.setVisible(true);
dialog.dispose();
int returnVal = dialog.getReturn();
if (returnVal == DamageDialog.OK_VALUE)
{
int damage = dialog.getDamage();
if (dialog.getSubdual())
{
if (subdualType == PreferencesDamagePanel.DAMAGE_SUBDUAL)
{
doSubdual(damage);
}
else if (subdualType == PreferencesDamagePanel.DAMAGE_NON_LETHAL)
{
doNonLethal(damage);
}
}
else
{
doDamage(damage);
}
}
}
/** Deletes the selected combatants from the Init List */
private void deleteCombatant()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
try
{
InitHolder iH = selectedList.remove(0);
initList.remove(iH);
removeTab(iH);
}
catch (Exception e)
{
// TODO: Exception Needs to be handled
}
}
initList.sort();
refreshTable();
}
/**
* Do an amount of damage to the selected combatants
*
*@param damage The amount of damage to do
*/
private void doDamage(int damage)
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
doDamage(damage, selectedList.remove(0));
}
initList.sort();
refreshTable();
}
/**
* <p>Damages specified combatant. This allows other methods to damage
* combatants who are not necessarily selected at the time.</p>
*
* @param damage
* Points of damage to do.
* @param iH
* InitHolder to damage.
*/
private void doDamage(int damage, InitHolder iH)
{
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
State oldStatus = cbt.getStatus();
cbt.damage(damage);
State newStatus = cbt.getStatus();
writeToCombatTabWithRound(cbt.getName() + " (" + cbt.getPlayer()
+ ") Took " + damage + " Damage: " + cbt.getHP().getCurrent()
+ "/" + cbt.getHP().getMax());
doMassiveDamage(cbt, damage);
if ((oldStatus != newStatus) && (newStatus == State.Dead))
{
combatantDied(cbt);
}
}
}
//** End Functions implementing button calls for the bottom toolbar **
//** Functions called by dialogs **
/**
* Do an amount of healing to the selected combatants
*
*@param heal The amount of healing to do
*/
private void doHeal(int heal)
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
cbt.heal(heal);
combatantUpdated(cbt);
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Gained " + heal + " Healing: "
+ cbt.getHP().getCurrent() + "/" + cbt.getHP().getMax());
}
}
initList.sort();
refreshTable();
}
/**
* Do Massive damage
* @param cbt
* @param damage
*/
private void doMassiveDamage(Combatant cbt, int damage)
{
int massiveType =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".Damage.Massive.Type",
PreferencesMassiveDamagePanel.MASSIVE_DND);
boolean isMassive = false;
if (massiveType == PreferencesMassiveDamagePanel.MASSIVE_DND)
{
isMassive = SystemHP.isDndMassive(cbt, damage);
}
else if (massiveType == PreferencesMassiveDamagePanel.MASSIVE_D20_MODERN)
{
isMassive = SystemHP.isD20ModernMassive(cbt, damage);
}
else if (massiveType == PreferencesMassiveDamagePanel.MASSIVE_HOUSE_HALF)
{
isMassive = SystemHP.isHouseHalfMassive(cbt, damage);
}
if (isMassive)
{
SavingThrowDialog dialog =
new SavingThrowDialog(GMGenSystem.inst, true, cbt, 15,
SavingThrowDialog.FORT_SAVE);
dialog.setVisible(true);
dialog.dispose();
//Show the dialog and get it's results
int returnVal = dialog.getReturnValue();
int roll = dialog.getRoll();
int total = dialog.getTotal();
int dc = dialog.getDC();
//Create a message out with the results
StringBuilder sb = new StringBuilder();
sb.append(dialog.getSaveAbbrev(dialog.getSaveType()));
sb.append(" save DC " + dc);
if (roll > 0)
{
sb.append(" with a roll of " + (roll + total));
sb.append(" (" + total + " + Roll: " + roll + ")");
}
//write out the results to the combat tab
if (returnVal == SavingThrowDialog.PASS_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Passed a " + sb
+ " to avoid massive damage effects");
}
else if (returnVal == SavingThrowDialog.FAIL_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Failed a " + sb
+ " to avoid massive damage effects");
//Failure
int massiveEffect =
SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME
+ ".Damage.Massive.Effect",
PreferencesMassiveDamagePanel.MASSIVE_EFFECT_KILL);
if (massiveEffect == PreferencesMassiveDamagePanel.MASSIVE_EFFECT_KILL)
{
cbt.kill();
combatantDied(cbt);
}
else if (massiveEffect == PreferencesMassiveDamagePanel.MASSIVE_EFFECT_NEGATIVE)
{
SystemHP hp = cbt.getHP();
int current = hp.getCurrent();
cbt.damage(current + 1);
}
else if (massiveEffect == PreferencesMassiveDamagePanel.MASSIVE_EFFECT_HALF_TOTAL)
{
SystemHP hp = cbt.getHP();
int max = hp.getMax();
cbt.damage(max / 2);
}
else if (massiveEffect == PreferencesMassiveDamagePanel.MASSIVE_EFFECT_HALF_CURRENT)
{
SystemHP hp = cbt.getHP();
int current = hp.getCurrent();
cbt.damage(current / 2);
}
}
}
combatantUpdated(cbt);
}
/**
* Do an amount of non-lethal damage to the selected combatants
*
*@param damage The amount of damage to do
*/
private void doNonLethal(int damage)
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
doNonLethal(damage, iH);
}
}
/**
* <p>Applies non-lethal combatant. This allows other methods to damage
* combatants who are not necessarily selected at the time.</p>
*
* @param damage
* Points of damage to do.
* @param iH
* InitHolder to damage.
*/
private void doNonLethal(int damage, InitHolder iH)
{
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
boolean isEnough = false;
if (cbt instanceof XMLCombatant)
{
XMLCombatant xmlcbt = (XMLCombatant) cbt;
if (damage > xmlcbt.getHP().getAttribute().getValue())
{
isEnough = true;
}
}
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))
{
isEnough = true;
}
}
if (isEnough)
{
SavingThrowDialog dialog =
new SavingThrowDialog(GMGenSystem.inst, true, cbt, 15,
SavingThrowDialog.FORT_SAVE);
dialog.setVisible(true);
dialog.dispose();
//Show the dialog and get it's results
int returnVal = dialog.getReturnValue();
int roll = dialog.getRoll();
int total = dialog.getTotal();
int dc = dialog.getDC();
//Create a message out with the results
StringBuilder sb = new StringBuilder();
sb.append(dialog.getSaveAbbrev(dialog.getSaveType()));
sb.append(" save DC " + dc);
if (roll > 0)
{
sb.append(" with a roll of " + (roll + total));
sb.append(" (" + total + " + Roll: " + roll + ")");
}
if (returnVal == SavingThrowDialog.PASS_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Passed a " + sb
+ " to avoid unconsiousness");
cbt.nonLethalDamage(false);
}
else if (returnVal == SavingThrowDialog.FAIL_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Failed a " + sb
+ " to avoid unconsiousness");
cbt.nonLethalDamage(true);
}
}
combatantUpdated(cbt);
}
}
/**
* Do an amount of subdual damage to the selected combatants
*
*@param damage The amount of damage to do
*/
private void doSubdual(int damage)
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
doSubdual(damage, iH);
}
initList.sort();
refreshTable();
}
/**
* <p>Applies subdual damage to combatant. This allows other methods to damage
* combatants who are not necessarily selected at the time.</p>
*
* @param damage
* Points of damage to do.
* @param iH
* InitHolder to damage.
*/
private void doSubdual(int damage, InitHolder iH)
{
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
cbt.subdualDamage(damage);
combatantUpdated(cbt);
writeToCombatTabWithRound(cbt.getName() + " (" + cbt.getPlayer()
+ ") Took " + damage + " Subdual Damage: "
+ cbt.getHP().getCurrent() + "(" + cbt.getHP().getSubdual()
+ "s)/" + cbt.getHP().getMax());
}
}
//** End Combat Tab Functions **
//** Toolbar & Button CoreUtility Functions **
/** Focuses the GUI on the Next Init button */
void focusNextInit()
{
bNextInit.grabFocus();
}
/** Focuses the GUI on the Roll button */
void focusRoll()
{
bRoll.grabFocus();
}
/** Heals the selected combatants */
private void healCombatant()
{
String inputValue =
JOptionPane.showInputDialog(this, "Heal", Integer.toString(1));
if (inputValue != null)
{
try
{
doHeal(Integer.parseInt(inputValue));
}
catch (NumberFormatException e)
{
healCombatant();
}
}
}
/** Finishes the initialization, by implementing the last portions of the user's preferences */
private void initLast()
{
int iDividerLocation =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".DividerLocation", 400);
jSplitPane1.setDividerLocation(iDividerLocation);
//Spell Tracking On
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doSpells", true))
{
bottomToolbar.add(bCast);
bottomToolbar.add(bEvent);
bottomToolbar.add(showEvents);
}
//Combat Tracking On
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doCombat", true))
{
bottomToolbar.add(bSave);
}
//HP Tracking On
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME + ".doHP",
true))
{
bottomToolbar.add(bDamage);
bottomToolbar.add(bHeal);
bottomToolbar.add(bStabilize);
}
//Death Tracking On
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true))
{
bottomToolbar.add(bKill);
bottomToolbar.add(bRaise);
bottomToolbar.add(showDead);
}
boolean bShowDead =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".ShowDead", false);
showDead.setSelected(bShowDead);
boolean bShowEvents =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".ShowEvents", true);
showEvents.setSelected(bShowEvents);
}
/**
* Initialization of the bulk of preferences. sets the defaults
* if this is the first time you have used this version
*/
private void initPrefs()
{
boolean prefsSet =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".arePrefsSet", false);
if (!prefsSet)
{
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".arePrefsSet", true);
}
Double version =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".Version", 0.0);
if ((version < 1.0) || !prefsSet)
{
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".doSpells", true);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME + ".doHP",
true);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".doMaxHP", 100);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".doMaxNum", 20);
SettingsHandler.setGMGenOption(
InitiativePlugin.LOG_NAME + ".doNum", 20);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.0", "#");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.0", 25);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.1", "Name");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.1", 100);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.2", "Player");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.2", 100);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.3", "Status");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.3", 75);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.4", "+");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.4", 25);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.5", "Init");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.5", 25);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.6", "Dur");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.6", 25);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.7", "HP");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.7", 25);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.8", "HP Max");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.8", 50);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName.9", "Type");
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth.9", 50);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".NumberOfColumns", 10);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".DividerLocation", 450);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".SubVersion", 1.0);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".Version", 1.0);
}
}
/** Kills the selected combatants */
private void killCombatant()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
cbt.kill();
combatantDied(cbt);
combatantUpdated(cbt);
}
}
initList.sort();
refreshTable();
}
/**
* Loads a character or party from an XML document
*
*@param character XML document containing a character or a party
* @param comp
*/
private void loadFromDocument(Document character, PCGenMessageHandler comp)
{
if (character.getRootElement().getName().equals("Party"))
{
Element party = character.getRootElement();
List xmlList = party.getChildren("Character");
for (Object aXmlList : xmlList)
{
Element eCharacter = (Element) aXmlList;
InitHolder combatant = new XMLCombatant(eCharacter);
initList.add(combatant);
}
List pcgList = party.getChildren("PcgCombatant");
for (Object aPcgList : pcgList)
{
Element eCharacter = (Element) aPcgList;
final PcgCombatant combatant =
new PcgCombatant(eCharacter, comp, messageHandler);
initList.add(combatant);
addTab(combatant);
}
List eventList = party.getChildren("Event");
for (Object anEventList : eventList)
{
Element eCharacter = (Element) anEventList;
InitHolder combatant = new Event(eCharacter);
initList.add(combatant);
}
List spellList = party.getChildren("Spell");
for (Object aSpellList : spellList)
{
Element eCharacter = (Element) aSpellList;
InitHolder combatant = new Spell(eCharacter);
initList.add(combatant);
}
initList.calculateNumberField();
}
else if (character.getRootElement().getName().equals("Character"))
{
Element eCharacter = character.getRootElement();
InitHolder combatant = new XMLCombatant(eCharacter);
initList.add(combatant);
}
}
/**
* Perform initial loading
* @param initFile
* @param comp
*/
public void loadINIT(File initFile, PCGenMessageHandler comp)
{
try
{
SAXBuilder builder = new SAXBuilder();
Document character = builder.build(initFile);
loadFromDocument(character, comp);
}
catch (Exception e)
{
JOptionPane.showMessageDialog(JOptionPane
.getFrameForComponent(this), "File load error: "
+ initFile.getName());
Logging.errorPrint("File Load Error" + initFile.getName());
Logging.errorPrint(e.getMessage(), e);
}
}
/** Moves to the next active initiative */
private void nextInit()
{
int oldInit = currentInit;
setCurrentInit(currentInit - 1);
int bleedingTime =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".Damage.Dying", PreferencesDamagePanel.DAMAGE_DYING_END);
for (int i = 0; i < initList.size(); i++)
{
InitHolder iH = initList.get(i);
if (iH instanceof Event)
{
Event e = (Event) iH;
int eInit = e.getInitiative().getCurrentInitiative();
if (oldInit == eInit)
{
int duration = e.decDuration();
if (duration < 0)
{
writeToCombatTabWithRound(e.getPlayer() + "'s "
+ e.getName() + " ended");
if (e.isAlert())
{
JOptionPane.showMessageDialog(this, e.getEndText());
}
initList.remove(i);
}
}
}
else if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
int cInit = cbt.getInitiative().getCurrentInitiative();
if (oldInit == cInit)
{
cbt.decDuration();
if (bleedingTime == PreferencesDamagePanel.DAMAGE_DYING_INITIATIVE)
{
bleed((Combatant) iH);
}
}
}
}
if (currentInit <= 0)
{
int maxInit = initList.getMaxInit();
setCurrentInit(maxInit);
for (InitHolder anInitList : initList)
{
if (bleedingTime == PreferencesDamagePanel.DAMAGE_DYING_END)
{
if (anInitList instanceof Combatant)
{
bleed((Combatant) anInitList);
}
}
anInitList.endRound();
}
round++;
writeToCombatTab("Round " + round);
setCurrentInit(maxInit);
}
else if (!initList.initValid(currentInit))
{
nextInit();
}
refreshTable();
}
/** pastes the copied combatant
* @param toPaste
*/
private void pasteNew(InitHolder toPaste)
{
if (toPaste instanceof XMLCombatant)
{
XMLCombatant cb = (XMLCombatant) toPaste;
SystemInitiative init = cb.getInitiative();
SystemHP hitPoints = cb.getHP();
String name = initList.getUniqueName(cb.getName());
InitHolder newCbt = new XMLCombatant(name, toPaste.getPlayer(), init
.getAttribute().getValue(), hitPoints.getAttribute()
.getValue(), hitPoints.getMax(),
hitPoints.getCurrent(), hitPoints.getSubdual(), init
.getBonus(), cb.getCombatantType(), cb.getCR());
initList.add(newCbt);
}
if (toPaste instanceof PcgCombatant)
{
// PcgCombatant cb = (PcgCombatant) toPaste;
// PCGen_Frame1.getInst().loadPCFromFile(
// new File(cb.getPC().getFileName()), false, true);
// As character exists in pcgen it is automatically added in to the init list
}
refreshTable();
}
/**
* Pastes num copies of the copied combatant
* @param toPaste
*
*@param num number to paste
*/
private void pasteNew(InitHolder toPaste, int num)
{
for (int i = 0; i < num; i++)
{
pasteNew(toPaste);
}
}
/**
* <p>Performs an attack action for the specified combatant. This method
* constructs an AttackModel from the specified string and displays an attack
* dialog.</p>
* <p>If other combatants are present, this method passes the attack dialog
* a list of such combatants, and the user can choose to damage one or more of them.
* Deceased combatants are removed from this list, as is the current combatant.</p>
*
* @param attack
* @param combatant
*/
private void performAttack(AttackModel attack, InitHolder combatant)
{
Vector combatants = new Vector(initList.size());
combatants.addAll(
initList.stream()
.filter(anInitList -> (anInitList instanceof PcgCombatant)
&& (anInitList != combatant)
&& ((anInitList.getStatus() != State.Dead) || showDead.isSelected())
)
.collect(Collectors.toList()));
AttackDialog dlg = new AttackDialog(attack, combatants);
dlg.setModal(true);
dlg.setVisible(true);
final List<Integer> dmgList = dlg.getDamageList();
final List targetList = dlg.getDamagedCombatants();
if ((dmgList != null) && (targetList != null) && (!dmgList.isEmpty())
&& (!targetList.isEmpty()))
{
writeToCombatTabWithRound(combatant.getName()
+ " successfully attacks using " + attack);
for (int i = 0; (i < dmgList.size()) && (i < targetList.size()); i++)
{
if (dlg.isSubdual())
{
int subdualType =
SettingsHandler.getGMGenOption(
InitiativePlugin.LOG_NAME + ".Damage.Subdual",
PreferencesDamagePanel.DAMAGE_SUBDUAL);
if (subdualType == PreferencesDamagePanel.DAMAGE_SUBDUAL)
{
doSubdual(dmgList.get(i),
(InitHolder) targetList.get(i));
}
else if (subdualType == PreferencesDamagePanel.DAMAGE_NON_LETHAL)
{
doNonLethal(dmgList.get(i),
(InitHolder) targetList.get(i));
}
}
else
{
doDamage(dmgList.get(i),
(InitHolder) targetList.get(i));
}
}
initList.sort();
refreshTable();
}
else if ((dmgList != null) && (!dmgList.isEmpty()))
{
writeToCombatTabWithRound(combatant.getName()
+ " successfully attacks using " + attack);
}
else
{
writeToCombatTabWithRound(combatant.getName()
+ " fails with attack using " + attack);
}
dlg.dispose();
}
/** Raises the selected combatants from the dead */
private void raiseCombatant()
{
final List selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = (InitHolder) selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
writeToCombatTabWithRound(iH.getName() + " (" + cbt.getPlayer()
+ ") Raised");
cbt.raise();
combatantUpdated(cbt);
}
}
initList.sort();
refreshTable();
}
/** Refocuses the selected combatants */
private void refocusCombatant()
{
final List selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = (InitHolder) selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
cbt.init.refocus();
combatantUpdated(cbt);
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Refocused");
}
}
initList.sort();
refreshTable();
}
//** Table CoreUtility Functions **
/** Refreshes the main table to reflect the current data in memory */
public void refreshTable()
{
combatantTable.clearSelection();
DefaultTableModel model = (DefaultTableModel) combatantTable.getModel();
model.setNumRows(0);
int startSelect = -1;
int rowNum = 0;
for (int i = 0; i < initList.size(); i++)
{
InitHolder c = initList.get(i);
if (((c.getStatus() != State.Dead) || showDead.isSelected())
&& (!(c instanceof Event) || showEvents.isSelected()))
{
Vector rowVector = initList.getRowVector(i, columnList);
model.addRow(rowVector);
int cInit = c.getInitiative().getCurrentInitiative();
if (cInit == currentInit)
{
if (startSelect == -1)
{
startSelect = rowNum;
}
combatantTable.setRowSelectionInterval(startSelect, rowNum);
}
rowNum++;
}
}
refreshEventTab();
}
//** End Initialization Functions **
/**
* Refresh the tabs
*/
public void refreshTabs()
{
initList.stream()
.filter(anInitList ->
((anInitList.getStatus() != State.Dead) || showDead.isSelected())
&& (anInitList instanceof Combatant))
.forEach(anInitList ->
{
Combatant cbt = (Combatant) anInitList;
removeTab(cbt);
addTab(cbt);
});
}
/**
* Remove the pcg combatant
* @param pc
*/
public void removePcgCombatant(PlayerCharacter pc)
{
for (int i = 0; i < initList.size(); i++)
{
InitHolder iH = initList.get(i);
if (iH instanceof PcgCombatant)
{
PcgCombatant c = (PcgCombatant) iH;
if (c.getPC() == pc)
{
initList.remove(iH);
removeTab(iH);
}
}
}
}
/**
* Remove the tab
* @param iH
*/
private void removeTab(InitHolder iH)
{
try
{
tpaneInfo.removeTabAt(tpaneInfo.indexOfTab(iH.getName()));
}
catch (Exception e)
{
// TODO: Exception Needs to be handled
}
}
/**
* Remove the named tab
* @param name The name of the tab to remove
*/
private void removeTab(String name)
{
try
{
tpaneInfo.removeTabAt(tpaneInfo.indexOfTab(name));
}
catch (IndexOutOfBoundsException e)
{
// Ignore - means the name was not recognised
}
}
/** Re-rolls the selected combatant's initiatives */
private void rerollCombatant()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
cbt.init.check();
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Rerolled");
combatantUpdated(cbt);
}
}
initList.sort();
refreshTable();
}
//** End Toolbar & Button CoreUtility Functions **
//** Functions implementing button calls for top toolbar **
/** Starts a new combat, and rolls a new initiative for all combatants */
private void roll()
{
round = 0;
initList.check();
int maxInit = initList.getMaxInit();
writeToCombatTab("Combat Number " + currentCombat + ": ");
writeToCombatTab("Round 1");
currentCombat++;
round = 1;
setCurrentInit(maxInit);
}
//** End Functions implementing button calls for top toolbar **
//** Functions implementing button calls for the bottom toolbar **
/**
* Save the initiative roll
*/
private void rollSave()
{
final List<InitHolder> selectedList = getSelected();
//int dc = 0;
//int type = SavingThrowDialog.NULL_SAVE;
SaveModel model = new SaveModel();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
if (iH instanceof Combatant)
{
model = performSave(model, iH);
}
}
refreshTable();
}
private SaveModel performSave(SaveModel model, InitHolder iH)
{
Combatant cbt = (Combatant) iH;
SavingThrowDialog dialog =
new SavingThrowDialog(GMGenSystem.inst, true, cbt, model);
dialog.setVisible(true);
dialog.dispose();
int returnVal = dialog.getReturnValue();
int roll = dialog.getRoll();
int total = dialog.getTotal();
model = dialog.getSaveModel();
StringBuilder sb = new StringBuilder();
sb.append(dialog.getSaveAbbrev(dialog.getSaveType()));
sb.append(" save DC " + model.getDc());
if (roll > 0)
{
sb.append(" with a roll of " + (roll + total));
sb.append(" (" + total + " + Roll: " + roll + ")");
}
if (returnVal == SavingThrowDialog.PASS_OPTION)
{
writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer()
+ ") Passed a " + sb);
}
else if (returnVal == SavingThrowDialog.FAIL_OPTION)
{
writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer()
+ ") Failed a " + sb);
}
return model;
}
/**
* Saves the current combatants out to an XML file
*
*@param xml The File to save to
*@exception Exception XML and file IO exceptions
*/
private void saveToDocument(File xml) throws IOException
{
Element party = new Element("Party");
party.setAttribute("filever", "1.0");
party.setAttribute("filetype", "initsave");
/*if(currentInit > -1) {
party.setAttribute("current_init", Integer.toString(currentInit));
}*/
initList.forEach((InitHolder anInitList) -> party.addContent(anInitList.getSaveElement()));
XMLOutputter xmlOut = new XMLOutputter();
xmlOut.setFormat(Format.getRawFormat().setEncoding("US-ASCII"));
try (Writer fr = new FileWriter(xml))
{
Document saveDocument = new Document(party);
xmlOut.output(saveDocument, fr);
fr.flush();
fr.close();
}
}
//** End Preferences Functions **
//** IO Functions **
/** Calls up a file save dialog, and if a file is selected/created, will then save the combatants out to disk. */
public void saveToFile()
{
JFileChooser fLoad = new JFileChooser();
File defaultFile = new File(PCGenSettings.getPcgDir());
if (defaultFile.exists())
{
fLoad.setCurrentDirectory(defaultFile);
}
String[] fileExt = {"gmi", "init"};
FileFilter sff =
new SimpleFileFilter(fileExt,
"GMGen Initiative/Encounter Export");
fLoad.addChoosableFileFilter(sff);
fLoad.setFileFilter(sff);
final int returnVal = fLoad.showSaveDialog(this);
try
{
if (returnVal == JFileChooser.APPROVE_OPTION)
{
String fileName = fLoad.getSelectedFile().getName();
String ext = "";
if (!fileName.endsWith(".gmi"))
{
ext = ".gmi";
}
File xml =
new File(fLoad.getSelectedFile().getParent()
+ File.separator + fileName + ext);
if (xml.exists())
{
int choice =
JOptionPane.showConfirmDialog(this,
"File Exists, Overwrite?", "File Exists",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (choice == JOptionPane.YES_OPTION)
{
SettingsHandler.ensurePathExists(xml.getParentFile());
saveToDocument(xml);
}
}
else
{
SettingsHandler.ensurePathExists(xml.getParentFile());
saveToDocument(xml);
}
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "Error Writing File");
Logging.errorPrint("Error Writing File");
Logging.errorPrint(e.getMessage(), e);
}
}
/** Stabilizes the selected combatants */
private void stabilizeCombatant()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
if (iH instanceof Combatant)
{
Combatant cbt = (Combatant) iH;
writeToCombatTabWithRound(iH.getName() + " (" + cbt.getPlayer()
+ ") Stabilized");
cbt.stabilize();
combatantUpdated(cbt);
}
}
initList.sort();
refreshTable();
}
/** Calls up the CastSpell dialog, passing in the data for the first selected combatant, if there is one*/
private void startEvent()
{
final List<InitHolder> selectedList = getSelected();
while (!selectedList.isEmpty())
{
InitHolder iH = selectedList.remove(0);
StartEvent dialog =
new StartEvent(JOptionPane.getFrameForComponent(this),
true, this, iH.getPlayer(), iH.getInitiative()
.getCurrentInitiative());
dialog.setVisible(true);
refreshTable();
return;
}
initList.sort();
refreshTable();
StartEvent dialog =
new StartEvent(JOptionPane.getFrameForComponent(this), true,
this);
dialog.setVisible(true);
refreshTable();
}
//** End IO Functions **
//** Combat Tab Functions **
/**
* Writes out a message to the Combat window
*
*@param message Message to write to the Data window
*/
private void writeToCombatTab(String message)
{
log.logMessage(InitiativePlugin.LOG_NAME, message);
}
/**
* Writes out a message to the Combat window, and includes the initiative that the message was written at
*
*@param message Message to write to the Data window
*/
void writeToCombatTabWithRound(String message)
{
writeToCombatTab(" (Round: " + round + ", Init: " + currentInit + "): "
+ message);
}
/**
* <p>Called when a hyperlink is selected in one of the text panes in {@code tpaneInfo}.
* Used to generate attack/skill, etc. dialogs.</p>
*
* @param e {@code HyperLinkEvent} that called this method.
* @param cbt {@code PcgCombatant} to perform action for.
*/
private void hyperLinkSelected(HyperlinkEvent e, InitHolder cbt)
{
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
{
PObjectModel model = PObjectModel.Factory(e.getDescription());
if (model != null)
{
if ((model instanceof AttackModel) && (cbt instanceof PcgCombatant))
{
InitHolder pcgcbt = cbt;
performAttack((AttackModel) model, pcgcbt);
}
else if (model instanceof CheckModel)
{
performCheck((CheckModel) model);
}
else if (model instanceof SpellModel)
{
castSpell((SpellModel) model, cbt);
}
else if (model instanceof SaveModel)
{
performSave((SaveModel) model, cbt);
}
else if ((model instanceof DiceRollModel)
&& (cbt instanceof PcgCombatant))
{
performDiceRoll((DiceRollModel) model);
}
}
}
}
/**
* <p>
* Performs the specified dice roll by raising a dice roll dialog.
* </p>
*
* @param model The dice roll model
*/
private void performDiceRoll(DiceRollModel model)
{
DiceRollDialog dlg = new DiceRollDialog(model);
dlg.setModal(true);
dlg.setVisible(true);
dlg.dispose();
}
/**
* <p>
* Fired when the selection in the {@code combatantTable} changes;
* if any rows are selected, it synchronizes the tab view with the first
* selected row.
* </p>
*
* @param e
* {@code ListSelectionEvent} which fired this method
*/
private void listSelectionChaned(ListSelectionEvent e)
{
final int row = combatantTable.getSelectedRow();
if (row >= 0)
{
final String name =
(String) combatantTable.getValueAt(row, combatantTable
.getColumnModel().getColumnIndex("Name"));
if ((name != null) && !name.isEmpty()
&& (tpaneInfo.indexOfTab(name) >= 0))
{
tpaneInfo.setSelectedIndex(tpaneInfo.indexOfTab(name));
}
}
}
private List getColumnOrder()
{
TableColumnModel colModel = combatantTable.getColumnModel();
final List colOrder = new ArrayList();
for (int i = 0; i < colModel.getColumnCount(); i++)
{
colOrder.add(colModel.getColumn(i).getHeaderValue());
}
return colOrder;
}
private void setColumnWidths(int[] widths)
{
TableColumnModel colModel = combatantTable.getColumnModel();
for (int i = 0; i < widths.length; i++)
{
TableColumn col = colModel.getColumn(i);
col.setPreferredWidth(widths[i]);
}
}
private void TablePopupActionPerformed(java.awt.event.ActionEvent evt)
{
checkAndFixColumns(tablePopupCBName.getState(), "Name");
checkAndFixColumns(tablePopupCBPlayer.getState(), "Player");
checkAndFixColumns(tablePopupCBStatus.getState(), "Status");
checkAndFixColumns(tablePopupCBPlus.getState(), "+");
checkAndFixColumns(tablePopupCBInitiative.getState(), "Init");
checkAndFixColumns(tablePopupCBDuration.getState(), "Dur");
checkAndFixColumns(tablePopupCBHP.getState(), "HP");
checkAndFixColumns(tablePopupCBHPMax.getState(), "HP Max");
checkAndFixColumns(tablePopupCBNumber.getState(), "#");
checkAndFixColumns(tablePopupCBType.getState(), "Type");
refreshTable();
}
private void addColumn(String name, int width)
{
DefaultTableModel tabModel =
(DefaultTableModel) combatantTable.getModel();
TableColumnModel colModel = combatantTable.getColumnModel();
tabModel.addColumn(name);
TableColumn column = colModel.getColumn(colModel.getColumnCount() - 1);
column.setPreferredWidth(width);
column.setWidth(width);
column.setIdentifier(name);
columnList = getColumnOrder();
}
private void addTableListener()
{
TableColumnModel colModel = combatantTable.getColumnModel();
colModel
.addColumnModelListener(new javax.swing.event.TableColumnModelListener()
{
@Override
public void columnAdded(
javax.swing.event.TableColumnModelEvent e)
{
colModAdded(e);
}
@Override
public void columnMarginChanged(
javax.swing.event.ChangeEvent e)
{
colModMarginChanged(e);
}
@Override
public void columnMoved(
javax.swing.event.TableColumnModelEvent e)
{
colModMoved(e);
}
@Override
public void columnRemoved(
javax.swing.event.TableColumnModelEvent e)
{
colModRemoved(e);
}
@Override
public void columnSelectionChanged(
javax.swing.event.ListSelectionEvent e)
{
colModSelectionChanged(e);
}
});
}
private void bAddCombatantActionPerformed(java.awt.event.ActionEvent evt)
{
addCombatant();
}
private void bCastActionPerformed(java.awt.event.ActionEvent evt)
{
castSpell();
focusNextInit();
}
private void bCombatantReRollActionPerformed(java.awt.event.ActionEvent evt)
{
rerollCombatant();
focusNextInit();
}
private void bDamageActionPerformed(java.awt.event.ActionEvent evt)
{
damageCombatant();
focusNextInit();
}
private void bDeleteActionPerformed(java.awt.event.ActionEvent evt)
{
deleteCombatant();
focusNextInit();
}
private void bEventActionPerformed(java.awt.event.ActionEvent evt)
{
startEvent();
focusNextInit();
}
private void bHealActionPerformed(java.awt.event.ActionEvent evt)
{
healCombatant();
focusNextInit();
}
private void bKillActionPerformed(java.awt.event.ActionEvent evt)
{
killCombatant();
focusNextInit();
}
private void bNextInitActionPerformed(java.awt.event.ActionEvent evt)
{
nextInit();
}
private void bRaiseActionPerformed(java.awt.event.ActionEvent evt)
{
raiseCombatant();
refreshTable();
focusNextInit();
}
private void bRefocusActionPerformed(java.awt.event.ActionEvent evt)
{
refocusCombatant();
focusNextInit();
}
private void bRollActionPerformed(java.awt.event.ActionEvent evt)
{
roll();
focusNextInit();
}
private void bSaveActionPerformed(java.awt.event.ActionEvent evt)
{
rollSave();
}
private void bStabilizeActionPerformed(java.awt.event.ActionEvent evt)
{
stabilizeCombatant();
refreshTable();
focusNextInit();
}
private void bleed(Combatant cbt)
{
if (cbt.getStatus() == State.Bleeding)
{
int stableType =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".Damage.Stable",
PreferencesDamagePanel.DAMAGE_STABLE_PERCENT);
if (stableType == PreferencesDamagePanel.DAMAGE_STABLE_PERCENT)
{
int roll = new Dice(1, 100).roll();
if (roll <= 10)
{
cbt.stabilize();
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") auto-stabilized (" + roll
+ "%)");
}
else
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") failed to auto-stabilize ("
+ roll + "%)");
}
}
else if (stableType == PreferencesDamagePanel.DAMAGE_STABLE_SAVE)
{
SavingThrowDialog dialog =
new SavingThrowDialog(GMGenSystem.inst, true, cbt, 20,
SavingThrowDialog.FORT_SAVE);
dialog.setVisible(true);
dialog.dispose();
//Show the dialog and get it's results
int returnVal = dialog.getReturnValue();
int roll = dialog.getRoll();
int total = dialog.getTotal();
int dc = dialog.getDC();
//stabilize if the combatant passes the save
if (dialog.getReturnValue() == SavingThrowDialog.PASS_OPTION)
{
cbt.stabilize();
}
//Create a message out with the results
StringBuilder sb = new StringBuilder();
sb.append(dialog.getSaveAbbrev(dialog.getSaveType()));
sb.append(" save DC " + dc);
if (roll > 0)
{
sb.append(" with a roll of " + (roll + total));
sb.append(" (" + total + " + Roll: " + roll + ")");
}
//write out the results to the combat tab
if (returnVal == SavingThrowDialog.PASS_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Passed a " + sb
+ " to auto-stabilize");
}
else if (returnVal == SavingThrowDialog.FAIL_OPTION)
{
writeToCombatTabWithRound(cbt.getName() + " ("
+ cbt.getPlayer() + ") Failed a " + sb
+ " to auto-stabilize");
}
}
State oldStatus = cbt.getStatus();
cbt.bleed();
combatantUpdated(cbt);
State newStatus = cbt.getStatus();
if ((oldStatus != newStatus) && (newStatus == State.Dead))
{
combatantDied(cbt);
}
}
}
/**
* <p>Casts a spell based on the specified spell model.</p>
*
* @param model A {@code SpellModel} instance
* @param combatant Combatant who is casting the spell.
*/
private void castSpell(SpellModel model, InitHolder combatant)
{
castSpell(model.getName(), combatant, model);
}
private void checkAndFixColumns(boolean shouldExist, String colName)
{
if (shouldExist && !getColumnOrder().contains(colName))
{
addColumn(colName, 100);
trackTable();
}
else if (!shouldExist && getColumnOrder().contains(colName))
{
removeColumn(colName);
}
}
/**
* <p>
* Generates a skill check dialog for a skill-check hyper link event.
* </p>
*
* @param model
* The skill model to roll with.
*/
private void performCheck(CheckModel model)
{
CheckDialog dlg = new CheckDialog(model);
dlg.setModal(true);
dlg.setVisible(true);
dlg.dispose();
}
private void colModAdded(javax.swing.event.TableColumnModelEvent evt)
{
// TODO: Method does nothing?
}
private void colModMarginChanged(javax.swing.event.ChangeEvent evt)
{
trackTable();
}
private void colModMoved(javax.swing.event.TableColumnModelEvent evt)
{
trackTable();
}
private void colModRemoved(javax.swing.event.TableColumnModelEvent evt)
{
// TODO: Method does nothing?
}
private void colModSelectionChanged(javax.swing.event.ListSelectionEvent evt)
{
// TODO: Method does nothing?
}
private void combatantTableMousePressed(java.awt.event.MouseEvent evt)
{
if (evt.isPopupTrigger())
{
initTablePopup();
tablePopup.show(evt.getComponent(), evt.getX(), evt.getY());
}
}
private void combatantTableMouseReleased(java.awt.event.MouseEvent evt)
{
if (evt.isPopupTrigger())
{
initTablePopup();
tablePopup.show(evt.getComponent(), evt.getX(), evt.getY());
}
}
private void combatantTablePropertyChange(java.beans.PropertyChangeEvent evt)
{
editTableRow();
refreshTable();
}
// TODO Change the Status to be a drop down list rather than a text field.
private void editTable(int row, int column)
{
// Figure out which row is the active row
// Karianna - Commented out this section to fix bug
/*
int activeRow = 0;
for (int i = 0; i < initList.size(); i++)
{
InitHolder c = initList.get(i);
// IF the InitHolder status is not Dead or showDead is selected (e.g. InitHolder is alive or we're showeing the dead)
// AND InitHolder is not an Event or we're shoeing events
// THEN update the active row
if ((c.getStatus() != Status.Dead || showDead.isSelected())
&& (!(c instanceof Event) || showEvents.isSelected()))
{
activeRow++;
}
}
*/
// Look up the active row (-1 as arrays are indexed starting at 0)
//InitHolder iH = initList.get(activeRow - 1);
InitHolder iH = initList.get(row);
String oldName = iH.getName();
Object data = combatantTable.getValueAt(row, column);
boolean atTop = (currentInit == initList.getMaxInit());
iH.editRow(columnList, column, data);
if (!iH.getName().equals(oldName) && (iH instanceof Combatant))
{
removeTab(oldName);
addTab((Combatant) iH);
}
initHolderUpdated(iH);
initList.sort();
if (atTop)
{
setCurrentInit(initList.getMaxInit());
}
refreshTable();
}
private void editTableRow()
{
int row = combatantTable.getEditingRow();
int column = combatantTable.getEditingColumn();
if ((row > -1) && (column > -1))
{
editTable(row, column);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
private void initComponents()
{//GEN-BEGIN:initComponents
tablePopup = new javax.swing.JPopupMenu();
tablePopupCBNumber = new javax.swing.JCheckBoxMenuItem();
tablePopupCBName = new javax.swing.JCheckBoxMenuItem();
tablePopupCBPlayer = new javax.swing.JCheckBoxMenuItem();
tablePopupCBStatus = new javax.swing.JCheckBoxMenuItem();
tablePopupCBPlus = new javax.swing.JCheckBoxMenuItem();
tablePopupCBInitiative = new javax.swing.JCheckBoxMenuItem();
tablePopupCBDuration = new javax.swing.JCheckBoxMenuItem();
tablePopupCBHP = new javax.swing.JCheckBoxMenuItem();
tablePopupCBHPMax = new javax.swing.JCheckBoxMenuItem();
tablePopupCBType = new javax.swing.JCheckBoxMenuItem();
final javax.swing.JToolBar topToolbar = new javax.swing.JToolBar();
final javax.swing.JPanel buttonPanelTop = new javax.swing.JPanel();
bRoll = new javax.swing.JButton();
final JButton bAddCombatant = new JButton();
bNextInit = new javax.swing.JButton();
final JButton bRefocus = new JButton();
bCombatantReRoll = new javax.swing.JButton();
bDelete = new javax.swing.JButton();
final javax.swing.JPanel jPanel2 = new javax.swing.JPanel();
lCounter = new javax.swing.JLabel();
jSplitPane1 = new FlippingSplitPane();
final javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
final javax.swing.JScrollPane jScrollEvents = new javax.swing.JScrollPane();
combatantTable = new javax.swing.JTable();
tpaneInfo = new javax.swing.JTabbedPane();
tpCombatInfo = new javax.swing.JTextArea();
tpCombatInfo.setName("Events");
bottomToolbar = new javax.swing.JToolBar();
tablePopupCBNumber.setText("#");
tablePopupCBNumber
.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBNumber);
tablePopupCBName.setText("Name");
tablePopupCBName.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBName);
tablePopupCBPlayer.setText("Player");
tablePopupCBPlayer
.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBPlayer);
tablePopupCBStatus.setText("Status");
tablePopupCBStatus
.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBStatus);
tablePopupCBPlus.setText("Plus");
tablePopupCBPlus.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBPlus);
tablePopupCBInitiative.setText("Initiative");
tablePopupCBInitiative
.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBInitiative);
tablePopupCBDuration.setText("Duration");
tablePopupCBDuration
.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBDuration);
tablePopupCBHP.setText("HP");
tablePopupCBHP.setEnabled(false);
tablePopupCBHP.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBHP);
tablePopupCBHPMax.setText("HP Max");
tablePopupCBHPMax.setEnabled(false);
tablePopupCBHPMax.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBHPMax);
tablePopupCBType.setText("Type");
tablePopupCBType.addActionListener(this::TablePopupActionPerformed);
tablePopup.add(tablePopupCBType);
setLayout(new java.awt.BorderLayout());
setPreferredSize(new java.awt.Dimension(700, 600));
buttonPanelTop.setLayout(new javax.swing.BoxLayout(buttonPanelTop,
javax.swing.BoxLayout.X_AXIS));
bAddCombatant.setText("Add Combatant");
bAddCombatant.addActionListener(this::bAddCombatantActionPerformed);
buttonPanelTop.add(bAddCombatant);
bDuplicateCombatant.setText("Duplicate");
bDuplicateCombatant.setEnabled(false);
bDuplicateCombatant
.addActionListener(this::bDuplicateCombatantActionPerformed);
bDelete.setText("Delete");
bDelete.addActionListener(this::bDeleteActionPerformed);
buttonPanelTop.add(bDelete);
buttonPanelTop.add(bDuplicateCombatant);
buttonPanelTop.add(new JSeparator());
bRoll.setText("Start Combat");
bRoll.addActionListener(this::bRollActionPerformed);
buttonPanelTop.add(bRoll);
bCombatantReRoll.setText("Roll");
bCombatantReRoll.addActionListener(this::bCombatantReRollActionPerformed);
buttonPanelTop.add(bCombatantReRoll);
bNextInit.setText("Next Initiative");
bNextInit.addActionListener(this::bNextInitActionPerformed);
buttonPanelTop.add(bNextInit);
buttonPanelTop.add(new JSeparator());
bRefocus.setText("Refocus");
bRefocus.addActionListener(this::bRefocusActionPerformed);
buttonPanelTop.add(bRefocus);
buttonPanelTop.add(new JSeparator());
bRefresh.setText("Refresh Tabs");
bRefresh.addActionListener(evt ->
{
refreshTable();
refreshTabs();
});
buttonPanelTop.add(bRefresh);
topToolbar.add(buttonPanelTop);
topToolbar.add(jPanel2);
topToolbar.add(lCounter);
add(topToolbar, java.awt.BorderLayout.NORTH);
jSplitPane1.setDividerLocation(400);
jSplitPane1.setOneTouchExpandable(true);
jSplitPane1.setPreferredSize(new java.awt.Dimension(800, 405));
combatantTable.addMouseListener(new java.awt.event.MouseAdapter()
{
@Override
public void mousePressed(java.awt.event.MouseEvent e)
{
combatantTableMousePressed(e);
}
@Override
public void mouseReleased(java.awt.event.MouseEvent e)
{
combatantTableMouseReleased(e);
}
});
combatantTable
.addPropertyChangeListener(this::combatantTablePropertyChange);
combatantTable.getSelectionModel().addListSelectionListener(
e ->
{
boolean hasSelection = combatantTable.getSelectedRow() > -1;
bDuplicateCombatant.setEnabled(hasSelection);
bDelete.setEnabled(hasSelection);
bCombatantReRoll.setEnabled(hasSelection);
});
jScrollPane1.setViewportView(combatantTable);
jScrollEvents.setViewportView(tpCombatInfo);
jSplitPane1.setLeftComponent(jScrollPane1);
tpaneInfo.addTab("Events", jScrollEvents);
jSplitPane1.setRightComponent(tpaneInfo);
add(jSplitPane1, java.awt.BorderLayout.CENTER);
add(bottomToolbar, java.awt.BorderLayout.SOUTH);
bottomToolbar.add(bOpposedSkill);
}
/**
* @param evt
*/
private void bDuplicateCombatantActionPerformed(ActionEvent evt)
{
//TODO: This only works for saved pcgen files and xml combatants.
//For pcgen files, it reloads the file, since there's no good way
//curently to clone a PlayerCharacter.
DefaultFormatter formatter = new NumberFormatter();
formatter.setAllowsInvalid(false);
formatter.setCommitsOnValidEdit(true);
formatter.setValueClass(Integer.class);
JFormattedTextField field = new JFormattedTextField(formatter);
field.setValue(1);
int choice =
JOptionPane.showConfirmDialog(GMGenSystem.inst, field,
"How many copies?", JOptionPane.OK_CANCEL_OPTION);
if (choice == JOptionPane.CANCEL_OPTION)
{
return;
}
int count = ((Number) field.getValue()).intValue();
for (InitHolder holderToCopy : getSelected())
{
if ((holderToCopy instanceof XMLCombatant)
|| (holderToCopy instanceof PcgCombatant))
{
if (holderToCopy instanceof PcgCombatant)
{
if ((((PcgCombatant) holderToCopy).getPC().getFileName() != null)
&& (!((PcgCombatant) holderToCopy).getPC().getFileName().isEmpty()))
{
pasteNew(holderToCopy, count);
}
else
{
JOptionPane
.showMessageDialog(
GMGenSystem.inst,
"Combatant "
+ holderToCopy.getName()
+ " cannot be duplicated because it has not been saved to a valid .pcg file.",
"Cannot Duplicate", JOptionPane.WARNING_MESSAGE);
}
}
else
{
pasteNew(holderToCopy, count);
}
}
else
{
JOptionPane
.showMessageDialog(
GMGenSystem.inst,
"Combatant "
+ holderToCopy.getName()
+ " cannot be duplicated because it is not a PCGen or XML combatant.",
"Cannot Duplicate", JOptionPane.WARNING_MESSAGE);
}
}
}
//GEN-END:initComponents
//** Initialization Functions **
private void initDynamicComponents()
{
bSave.setText("Roll Save");
bSave.addActionListener(this::bSaveActionPerformed);
bCast.setText("Cast Spell");
bCast.addActionListener(this::bCastActionPerformed);
bEvent.setText("Start Event");
bEvent.addActionListener(this::bEventActionPerformed);
bKill.setText("Kill");
bKill.addActionListener(this::bKillActionPerformed);
bDamage.setText("Damage");
bDamage.addActionListener(this::bDamageActionPerformed);
bHeal.setText("Heal");
bHeal.addActionListener(this::bHealActionPerformed);
bStabilize.setText("Stabilize");
bStabilize.addActionListener(this::bStabilizeActionPerformed);
bRaise.setText("Raise");
bRaise.addActionListener(this::bRaiseActionPerformed);
showDead.setSelected(true);
showDead.setText("Show Dead");
showDead.addActionListener(this::showDeadActionPerformed);
showEvents.setSelected(true);
showEvents.setText("Show Events");
showEvents.addActionListener(this::showEventsActionPerformed);
bOpposedSkill.setText("Mass Skill Check");
bOpposedSkill.addActionListener(this::opposedSkillActionPerformed);
}
/**
* <p>
* Handles button press for bOpposedSkill. Opens the opposed check dialog.
* </p>
* @param e
*/
private void opposedSkillActionPerformed(ActionEvent e)
{
List<InitHolder> selected = getSelected();
List notSelected = getUnSelected();
OpposedCheckDialog dlg =
new OpposedCheckDialog(GMGenSystem.inst, selected, notSelected);
dlg.setModal(true);
dlg.setVisible(true);
dlg.dispose();
}
private void initTable()
{
initTableColumns();
JTableHeader header = combatantTable.getTableHeader();
header.addMouseListener(new java.awt.event.MouseAdapter()
{
@Override
public void mousePressed(java.awt.event.MouseEvent e)
{
combatantTableMousePressed(e);
}
@Override
public void mouseReleased(java.awt.event.MouseEvent e)
{
combatantTableMouseReleased(e);
}
});
columnList = getColumnOrder();
combatantTable.getSelectionModel().addListSelectionListener(
this::listSelectionChaned);
TableColumn typeColumn = combatantTable.getColumn("Type");
// These are the combobox values
String[] values = {"PC", "Enemy", "Ally", "Non Combatant"};
// Set the combobox editor on the 1st visible column
//int vColIndex = 0;
//TableColumn col = table.getColumnModel().getColumn(vColIndex);
typeColumn.setCellEditor(new TypeEditor(values));
//typeColumn.setCellRenderer(new TypeRenderer(values));
}
private void initTableColumns()
{
DefaultTableModel tabModel =
(DefaultTableModel) combatantTable.getModel();
tabModel.setColumnCount(0);
int colNo =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".NumberOfColumns", 0);
int[] widths = new int[colNo];
for (int i = 0; i < colNo; i++)
{
String name =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName." + i, "");
int width =
SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth." + i, 100);
addColumn(name, width);
widths[i] = width;
}
setColumnWidths(widths);
}
private void initTablePopup()
{
TableColumnModel colModel = combatantTable.getColumnModel();
int numCols = colModel.getColumnCount();
tablePopupCBName.setSelected(false);
tablePopupCBPlayer.setSelected(false);
tablePopupCBStatus.setSelected(false);
tablePopupCBPlus.setSelected(false);
tablePopupCBInitiative.setSelected(false);
tablePopupCBDuration.setSelected(false);
tablePopupCBHP.setSelected(false);
tablePopupCBHPMax.setSelected(false);
tablePopupCBNumber.setSelected(false);
tablePopupCBType.setSelected(false);
for (int i = 0; i < numCols; i++)
{
TableColumn col = colModel.getColumn(i);
String name = col.getIdentifier().toString();
switch (name)
{
case "Name":
tablePopupCBName.setSelected(true);
break;
case "Player":
tablePopupCBPlayer.setSelected(true);
break;
case "Status":
tablePopupCBStatus.setSelected(true);
break;
case "+":
tablePopupCBPlus.setSelected(true);
break;
case "Init":
tablePopupCBInitiative.setSelected(true);
break;
case "Dur":
tablePopupCBDuration.setSelected(true);
break;
case "HP":
tablePopupCBHP.setSelected(true);
break;
case "HP Max":
tablePopupCBHPMax.setSelected(true);
break;
case "#":
tablePopupCBNumber.setSelected(true);
break;
case "Type":
tablePopupCBType.setSelected(true);
break;
}
}
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doSpells", true)
|| SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doDeath", true)
|| SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doHP", true))
{
tablePopupCBDuration.setEnabled(true);
}
else
{
tablePopupCBDuration.setEnabled(false);
}
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME + ".doHP",
true))
{
tablePopupCBHP.setEnabled(true);
tablePopupCBHPMax.setEnabled(true);
}
else
{
tablePopupCBHP.setEnabled(false);
tablePopupCBHPMax.setEnabled(false);
}
if (SettingsHandler.getGMGenOption(InitiativePlugin.LOG_NAME
+ ".doNumber", true))
{
tablePopupCBNumber.setEnabled(true);
}
}
private void refreshEventTab()
{
tpCombatInfo.setText("");
for (final InitHolder anInitList : initList)
{
StringBuilder sb = new StringBuilder();
if (anInitList instanceof Event)
{
Event evt = (Event) anInitList;
sb.append(evt.getName() + " (" + evt.getPlayer() + ")\n");
sb.append("Duration: " + evt.getDuration() + "\n");
if (evt.getEffect().isEmpty())
{
sb.append("\n");
}
else
{
sb.append(evt.getEffect()).append("\n\n");
}
}
tpCombatInfo.setText(tpCombatInfo.getText() + sb);
}
}
private void removeColumn(String name)
{
TableColumnModel colModel = combatantTable.getColumnModel();
for (int i = 0; i < colModel.getColumnCount(); i++)
{
TableColumn col = colModel.getColumn(i);
if (col.getHeaderValue().toString().equals(name))
{
colModel.removeColumn(col);
}
}
trackTable();
initTable();
columnList = getColumnOrder();
}
private void showDeadActionPerformed(java.awt.event.ActionEvent evt)
{
checkDeadTabs();
refreshTable();
focusNextInit();
}
private void showEventsActionPerformed(java.awt.event.ActionEvent evt)
{
refreshTable();
focusNextInit();
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ShowEvents", showEvents.isSelected());
}
private void trackTable()
{
TableColumnModel colModel = combatantTable.getColumnModel();
int numCols = colModel.getColumnCount();
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".NumberOfColumns", numCols);
for (int i = 0; i < numCols; i++)
{
TableColumn col = colModel.getColumn(i);
String name = col.getIdentifier().toString();
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnName." + i, name);
SettingsHandler.setGMGenOption(InitiativePlugin.LOG_NAME
+ ".ColumnWidth." + i, col.getWidth());
}
}
/**
* Update the initiative holder
* @param iH
*/
private void initHolderUpdated(InitHolder iH)
{
if (iH instanceof Combatant)
{
combatantUpdated((Combatant) iH);
}
}
/**
* Send a message stating that the combatant has been updated
* @param cbt
*/
private void combatantUpdated(Combatant cbt)
{
messageHandler.handleMessage(new CombatantHasBeenUpdatedMessage(GMGenSystem.inst, cbt));
}
//** End Other Variables **
/**
* A cell editor
*/
private static final class TypeEditor extends DefaultCellEditor
{
/**
* Constructor
* @param items
*/
private TypeEditor(String[] items)
{
super(new JComboBox(items));
}
}
/**
* A table cell renderer
*/
@SuppressWarnings("ALL")
public static class TypeRenderer extends JComboBox implements
TableCellRenderer
{
/**
* Constructor
* @param items
*/
public TypeRenderer(String[] items)
{
super(items);
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
if (isSelected)
{
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
}
else
{
setForeground(table.getForeground());
setBackground(table.getBackground());
}
// Select the current value
setSelectedItem(value);
return this;
}
}
}