Implemented read/write of saved characters, currently a Tester.java file tests the ability to save and read saved characters, and the Application has a rudimentary GUI interface to choose to load a specific save file and see information about that character.

This commit is contained in:
Josh Ashton
2022-11-29 17:50:28 -07:00
parent 67624b18b5
commit 4d5fd7c952
38 changed files with 498 additions and 170 deletions
+58
View File
@@ -1,2 +1,60 @@
# Application # Application
CSIS 1410 - Group Project CSIS 1410 - Group Project
CURRENT TODO ITEMS:
**************** CONTENT ****************
- All PHB classes should be included.
**************** GUI ********************
- Finish GUI panels
PANELS:
- Race
Upload custom profile picture button.
- Description (needs positioning)
- Spells & Equipment
- Preview
- Load Character/View character
- Save as PDF / Print
DESCRIPTIONS:
- Class action scene pictures.
- Ability Scores description text.
- Class descriptions.
- Race descriptions.
*************** FILES ******************
NOTE: user.dir = /home/joshuaashton/Development/misc/dndApp/src
user.home = /home/joshuaashton
NOTE: user.dir is changed to exe directory by application launch4j. This creates an exe file from .jar.
see Inno Setup Compiler to package .exe and the JRE into a singular installer.
- Upload custom profile picture.
- Character sheet from selections.
- Load existing characters to edit.
- Save new characters.
- File directory based upon OS used.
- Export to PDF.
- Print
************** FINAL TOUCHES **********
- Generate a random character.
- Character levels.
- Spells.
- Dice roller.
+1 -2
View File
@@ -2,9 +2,8 @@ public class App {
public static void main(String[] args) { public static void main(String[] args) {
FileManager data = new FileManager(); GUImanager gui = new GUImanager();
GUImanager gui = new GUImanager(data.isReturninguser());
gui.setVisible(true); gui.setVisible(true);
} }
+15 -2
View File
@@ -13,7 +13,16 @@ public class BasicNavPanel extends JPanel implements AppTheme {
super(new GridLayout(1, 2, 30, 0)); super(new GridLayout(1, 2, 30, 0));
this.backButton = backButton; this.backButton = backButton;
this.continueButton = continueButton;
if(continueButton == null) {
this.continueButton = null;
} else {
this.continueButton = continueButton;
}
this.continueRequirement = continueRequirement; this.continueRequirement = continueRequirement;
createNavPanel(); createNavPanel();
@@ -56,7 +65,11 @@ public class BasicNavPanel extends JPanel implements AppTheme {
if (continueRequirement == 0) { if (continueRequirement == 0) {
add(continueButton); if(continueButton != null) {
add(continueButton);
}
} else { } else {
+76 -59
View File
@@ -6,97 +6,113 @@ public class CharacterSheet implements Serializable {
private int heightFeet; private int heightFeet;
private int heightInch; private int heightInch;
private int weight; private int weight;
private String eye; private String eyeColor;
private String hair; private String hairColor;
private Race race; private Race race;
private ClassTemplate chClass;
private String[] spells;
private String[] equipment;
private String alignment;
private String background;
private CharacterStats stats; private CharacterStats stats;
/** /*
* @param name * TODO: Need to add the following variables:
* @param age *
* @param heightFeet * - CharacterClass x1 var
* @param heightInch * - ChosenSpells xN vars
* @param weight * - Equipment xN vars
* @param eye * - Description x3 vars
* @param hair *
* TOTAL: Minimum 12, + N spells and N equipment
*
*/ */
public CharacterSheet(String name, int age,
int heightFeet, int heightInch, public CharacterSheet(
int weight, String eye, String hair,
Race race, CharacterStats stats) { String name,
int age,
int heightFeet,
int heightInch,
int weight,
String eyeColor,
String hairColor,
Race race,
ClassTemplate chClass,
String alignment,
String background,
CharacterStats stats
) {
this.name = name; this.name = name;
this.age = age; this.age = age;
this.heightFeet = heightFeet; this.heightFeet = heightFeet;
this.heightInch = heightInch; this.heightInch = heightInch;
this.weight = weight; this.weight = weight;
this.eye = eye; this.eyeColor = eyeColor;
this.hair = hair; this.hairColor = hairColor;
this.race = race; this.race = race;
this.chClass = chClass;
this.alignment = alignment;
this.background = background;
this.stats = stats; this.stats = stats;
}
/**
* Default constructor
*/
public CharacterSheet() {
this.name = "null";
this.age = 0;
this.heightFeet = 0;
this.heightInch = 0;
this.weight = 0;
this.eye = "null";
this.hair = "null";
} }
/**
* @return the name
*/
public String getName() { public String getName() {
return name; return name;
} }
/**
* @return the age
*/
public int getAge() { public int getAge() {
return age; return age;
} }
/**
* @return the heightFeet
*/
public int getHeightFeet() { public int getHeightFeet() {
return heightFeet; return heightFeet;
} }
/**
* @return the heightInch
*/
public int getHeightInch() { public int getHeightInch() {
return heightInch; return heightInch;
} }
/**
* @return the weigth
*/
public int getWeight() { public int getWeight() {
return weight; return weight;
} }
/** public String getEyeColor() {
* @return the eye
*/ return eyeColor;
public String getEye() {
return eye;
} }
/** public String getHairColor() {
* @return the hair
*/ return hairColor;
public String getHair() {
return hair; }
public Race getRace() {
return race;
}
public ClassTemplate getCharacterClass() {
return chClass;
} }
public CharacterStats getStats() { public CharacterStats getStats() {
@@ -107,10 +123,11 @@ public class CharacterSheet implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "name: " + name + " | age: " + age + " | height: "
+ heightFeet + "\'" + heightInch + "\" | weight: " String output = "Character name: " + name + "\nAge: " + age + "\nHeight: " + heightFeet + "\'" + heightInch + "\"" + "\nWeight: " + weight + "\nEye Color: " + eyeColor + "\nHair Color: " + hairColor + "\nRace: " + race.toString() + "\nClass: " + chClass.toString() + "\nStats: " + stats.toString();
+ weight + " | eye: " + eye + " | hair: " + hair
+ " | race: " + race.toString() + " | stats: " + stats.toString(); return output;
} }
} }
+3 -1
View File
@@ -1,4 +1,6 @@
public class CharacterStats { import java.io.Serializable;
public class CharacterStats implements Serializable {
private Stats[] stats; private Stats[] stats;
+3 -1
View File
@@ -1,4 +1,6 @@
public class Charisma extends Stats { import java.io.Serializable;
public class Charisma extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
+3 -1
View File
@@ -1,4 +1,6 @@
public class Constitution extends Stats { import java.io.Serializable;
public class Constitution extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
-12
View File
@@ -1,12 +0,0 @@
import java.awt.*;
public interface CustomTheme {
public Color background = null;
public Color foreground = null;
Color getBackground();
Color getForeground();
}
+3 -1
View File
@@ -1,4 +1,6 @@
public class Dexterity extends Stats { import java.io.Serializable;
public class Dexterity extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
+20 -10
View File
@@ -1,4 +1,6 @@
public class Elf implements Race { import java.io.Serializable;
public class Elf implements Race, Serializable {
private final int speed = 30; private final int speed = 30;
private final int maxAge = 750; private final int maxAge = 750;
private String[] traits; private String[] traits;
@@ -14,57 +16,65 @@ public class Elf implements Race {
@Override @Override
public String getRace() { public String getRace() {
// TODO Auto-generated method stub
return this.getClass().getSimpleName(); return this.getClass().getSimpleName();
} }
@Override @Override
public int maxAge() { public int maxAge() {
// TODO Auto-generated method stub
return maxAge; return maxAge;
} }
@Override @Override
public int getSpeed() { public int getSpeed() {
// TODO Auto-generated method stub
return speed; return speed;
} }
@Override @Override
public String[] getTraits() { public String[] getTraits() {
// TODO Auto-generated method stub
return traits; return traits;
} }
@Override @Override
public String[] getSkills() { public String[] getSkills() {
// TODO Auto-generated method stub
return skills; return skills;
} }
@Override @Override
public String[] getLanguages() { public String[] getLanguages() {
// TODO Auto-generated method stub
return languages; return languages;
} }
@Override @Override
public String[] getProficiencies() { public String[] getProficiencies() {
// TODO Auto-generated method stub
return proficiencies; return proficiencies;
} }
@Override @Override
public int[] getASI() { public int[] getASI() {
// TODO Auto-generated method stub
return new int[]{1, 1}; return new int[]{1, 1};
} }
@Override @Override
public String toString() { public String toString() {
// TODO Auto-generated method stub
return this.getClass().getSimpleName(); return this.getClass().getSimpleName();
} }
} }
+11 -2
View File
@@ -1,4 +1,6 @@
public class Fighter implements ClassTemplate { import java.io.Serializable;
public class Fighter implements ClassTemplate, Serializable {
private int HP; private int HP;
@@ -7,7 +9,7 @@ public class Fighter implements ClassTemplate {
// TODO: This should be the type of die. // TODO: This should be the type of die.
private int hitDie; private int hitDie;
public Fighter(Stats[] stats, int level) { public Fighter() {
} }
@@ -85,4 +87,11 @@ public class Fighter implements ClassTemplate {
return null; return null;
} }
@Override
public String toString() {
return this.getClass().getSimpleName();
}
} }
+109 -61
View File
@@ -1,115 +1,163 @@
import java.awt.*; import java.awt.*;
import java.io.*; import java.io.*;
import java.util.*;
public class FileManager { public class FileManager {
private File[] savedCharacters; private String filepath;
private boolean returningUser;
private ArrayList<File> saveFiles;
private ArrayList<CharacterSheet> saves;
public FileManager() { public FileManager() {
findSavedCharacters(); filepath = System.getProperty("user.dir");
loadFonts(); saveFiles = new ArrayList<>();
setSaveFiles();
loadFont();
} }
private void loadFonts() { public String getOSFilepath() {
try { return filepath;
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File("SanSalvi.ttf")));
} catch (IOException | FontFormatException e) {
//Handle exception
System.out.println("Error finding font.");
}
} }
public boolean isReturninguser() { public boolean isReturningUser() {
if (savedCharacters == null) { return returningUser;
return false; }
} public CharacterSheet readSavedCharacter(int index) {
return savedCharacters.length > 0; return readCharacter(saveFiles.get(index));
} }
public CharacterSheet readCharacter(int index) { public void saveCharacter(CharacterSheet completedCharacter) {
CharacterSheet sheet = null; writeCharacter(completedCharacter);
try { }
FileInputStream fileIn = new FileInputStream("/dndBuilder/" + savedCharacters[index].getPath() + ".dnd"); public ArrayList<CharacterSheet> getSaves() {
ObjectInputStream in = new ObjectInputStream(fileIn);
sheet = (CharacterSheet) in.readObject();
in.close();
fileIn.close();
} catch (IOException i) { return saves;
i.printStackTrace(); }
} catch (ClassNotFoundException c) { // TODO: Need to implement.
public void deleteCharacter() {
System.out.println("Saved characters not found"); }
c.printStackTrace();
} private void loadFont() {
return sheet; try {
} GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
public void saveCharacter(CharacterSheet completedCharacter) { ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(filepath + "/.resources/SanSalvi.ttf")));
try { } catch(IOException | FontFormatException e) {
FileOutputStream fileOut = System.out.println("Filepath of font not found: " + filepath + "/.resources/SanSalvi.ttf does not exist.");
new FileOutputStream("/dndBuilder/" + completedCharacter.getName().hashCode() + ".dnd");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(completedCharacter);
out.close();
fileOut.close();
} catch (IOException i) { }
i.printStackTrace(); }
} private void setSaveFiles() {
findSavedCharacters(); File[] tmp = new File(filepath + "/.savedSheets/").listFiles();
} if(tmp != null) {
public void deleteCharacter(int index) { for(int i = 0; i < tmp.length; i++) {
File[] tmp = new File[savedCharacters.length - 1]; saveFiles.add(tmp[i]);
for (int i = 0; i < savedCharacters.length; i++) { }
if (i != index) { returningUser = true;
tmp[i] = savedCharacters[i]; } else {
} returningUser = false;
} }
savedCharacters = tmp; saves = new ArrayList<>();
findSavedCharacters(); for(File file : saveFiles) {
} saves.add(readCharacter(file));
private void findSavedCharacters() { }
savedCharacters = new File("/dndBuilder").listFiles(); }
} private CharacterSheet readCharacter(File file) {
CharacterSheet sheet = null;
System.out.println("filepath: " + file.getPath());
try {
FileInputStream fileIn = new FileInputStream(file.getPath());
ObjectInputStream in = new ObjectInputStream(fileIn);
sheet = (CharacterSheet) in.readObject();
in.close();
fileIn.close();
} catch (IOException | ClassNotFoundException e) {
System.out.println("No saved characters were found");
}
return sheet;
}
private void writeCharacter(CharacterSheet sheet) {
try(
FileOutputStream fileOut = new FileOutputStream(filepath + "/.savedSheets/" + sheet.getName() + ".dnd");
ObjectOutputStream objOut = new ObjectOutputStream(fileOut);
) {
System.out.println("Inside saving char method.");
objOut.writeObject(sheet);
setSaveFiles();
System.out.println("Object written to file.");
} catch (IOException e) {
System.out.println("ERROR: ");
e.printStackTrace();
System.out.println("\nERROR: Unable to write character sheet object to \n" + filepath + "/.savedSheets");
}
}
} }
+81 -11
View File
@@ -1,8 +1,13 @@
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.*;
public class GUImanager extends JFrame { public class GUImanager extends JFrame {
private FileManager fileManager;
private ArrayList<CharacterSheet> saves;
private ArrayList<DefaultButton> savesButtons;
private static JPanel[] panels; private static JPanel[] panels;
private int lastPanel; private int lastPanel;
private int currentPanel; private int currentPanel;
@@ -25,24 +30,23 @@ public class GUImanager extends JFrame {
private String[] backgroundDescriptions; private String[] backgroundDescriptions;
private int[] selectedStats; private int[] selectedStats;
public GUImanager() {
public GUImanager(boolean returningUser) {
super("D&D Character Builder"); super("D&D Character Builder");
fileManager = new FileManager();
frameSetup(); frameSetup();
setupPanelInfo(); setupPanelInfo();
this.panels = new JPanel[]{ this.panels = new JPanel[]{
new MainMenuPanel(createNewCharacterButton(), createRandomCharacterButton(), createLoadButton()), new MainMenuPanel(createNewCharacterButton(), createRandomCharacterButton(), createLoadButton()),
new BasicPanel(createNavPanel(), raceOptions, raceDescriptions, "Step 1: Choose Your Race"), // To choose Race. new BasicPanel(createNavPanel(), raceOptions, raceDescriptions, "Step 1: Choose Your Race"), // To choose Race.
new BasicPanel(createNavPanel(), classOptions, classDescriptions, "Step 2: Choose Your Class"), // To choose Class. new BasicPanel(createNavPanel(), classOptions, classDescriptions, "Step 2: Choose Your Class"), // To choose Class.
new ChooseAbilityScoresPanel(createNavPanel(1), statOptions, statDescriptions, selectedStats, "Step 3: Choose Your Ability Scores"), new ChooseAbilityScoresPanel(createNavPanel(1), statOptions, statDescriptions, selectedStats, "Step 3: Choose Your Ability Scores"),
new DescriptionPanel(createNavPanel(), characteristics, alignmentOptions, alignmentDescriptions, backgroundOptions, backgroundDescriptions, "Step 4: Describe your character") new DescriptionPanel(createNavPanel(), characteristics, alignmentOptions, alignmentDescriptions, backgroundOptions, backgroundDescriptions, "Step 4: Describe your character"),
new LoadCharacterPanel(createBackPanel(), loadableCharacters()),
new ViewCharacterPanel(createBackPanel(), new CharacterSheet("Josh", 21, 5, 8, 180, "Brown", "Dark Brown", new Elf(), new Fighter(), "Neutral", "Nomad", new CharacterStats(9, 15, 12, 10, 13, 10)))
}; };
/*
this.currentPanel = 0;
this.lastPanel = currentPanel - 1;
this.nextPanel = currentPanel + 1;*/
if (returningUser) { if (fileManager.isReturningUser()) {
this.currentPanel = 0; this.currentPanel = 0;
@@ -52,6 +56,9 @@ public class GUImanager extends JFrame {
} }
this.lastPanel = currentPanel - 1;
this.nextPanel = currentPanel + 1;
add(panels[currentPanel]); add(panels[currentPanel]);
} }
@@ -62,7 +69,7 @@ public class GUImanager extends JFrame {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
setPreferredSize(new Dimension(750, 550)); setPreferredSize(new Dimension(750, 550));
setSize(getPreferredSize()); setSize(getPreferredSize());
// setResizable(false); setResizable(false);
setLocationRelativeTo(null); setLocationRelativeTo(null);
try { try {
@@ -260,6 +267,12 @@ public class GUImanager extends JFrame {
} }
private BasicNavPanel createBackPanel() {
return new BasicNavPanel(createBackButton(), null, 0);
}
private DefaultButton createBackButton() { private DefaultButton createBackButton() {
DefaultButton button = new DefaultButton("Back"); DefaultButton button = new DefaultButton("Back");
@@ -305,6 +318,19 @@ public class GUImanager extends JFrame {
DefaultButton button = createContinueButton(); DefaultButton button = createContinueButton();
button.setText("Create New Character"); button.setText("Create New Character");
button.addActionListener(
e -> {
lastPanel = currentPanel;
currentPanel = 1;
nextPanel = 2;
clearAndReset();
}
);
return button; return button;
} }
@@ -361,8 +387,7 @@ public class GUImanager extends JFrame {
e -> { e -> {
lastPanel = currentPanel; lastPanel = currentPanel;
currentPanel = 3; currentPanel = 5;
nextPanel = currentPanel + 1;
clearAndReset(); clearAndReset();
} }
@@ -373,6 +398,50 @@ public class GUImanager extends JFrame {
} }
private ArrayList<DefaultButton> loadableCharacters() {
System.out.println("Loading characters...");
saves = fileManager.getSaves();
savesButtons = new ArrayList<>();
for(int i = 0; i < saves.size(); i++) {
savesButtons.add(createLoadNCharacterButton(i));
}
for(int i = 0; i < saves.size(); i++) {
System.out.println(saves.get(i).toString());
}
return savesButtons;
}
private DefaultButton createLoadNCharacterButton(int index) {
DefaultButton button = new DefaultButton(saves.get(index).getName());
button.addActionListener(
e -> {
lastPanel = currentPanel;
panels[5] = new ViewCharacterPanel(createBackPanel(), saves.get(index));
currentPanel = 5;
clearAndReset();
}
);
return button;
}
// TODO: Need to implement random character creation. // TODO: Need to implement random character creation.
private void createRandomCharacter() { private void createRandomCharacter() {
@@ -392,4 +461,5 @@ public class GUImanager extends JFrame {
} }
} }
+42
View File
@@ -11,6 +11,23 @@ public class ImageInfoPanel extends InfoPanel implements AppTheme {
private JLabel[][] portraits; private JLabel[][] portraits;
private int lastIndex; private int lastIndex;
//private JLabel[] savesPortraits;
//private int numSaveCharacters;
// TODO: Need to implement
/*
public ImageInfoPanel(int panelIndex, int numSaveCharacters) {
super(panelIndex);
this.numSaveCharacters = numSaveCharacters;
this.characterName = characterName;
createSavesPortraits();
}
*/
public ImageInfoPanel(String[] categoryHolder, String[] holderDescriptions, Rectangle[] bounds, int panelIndex) { public ImageInfoPanel(String[] categoryHolder, String[] holderDescriptions, Rectangle[] bounds, int panelIndex) {
super(categoryHolder, holderDescriptions, bounds, panelIndex); super(categoryHolder, holderDescriptions, bounds, panelIndex);
@@ -43,6 +60,31 @@ public class ImageInfoPanel extends InfoPanel implements AppTheme {
} }
// TODO: Need to create a separate class/refactor ImageInfoPanel to be multi-purpose.
/*
private void createSavesPortraits() {
File imagesDir;
imagesDir = new File("Img/.savesPortraits").listFiles();
savesPortraits = new JLabel[imagesDir.length);
int index = 0;
for(File file : imagesDir) {
savesPortraits[index] = image(file);
savesPortraits[index].setOpaque(true);
savesPortraits[index].setBackground(lightBrown);
savesPortraits[index].setBounds(bounds[3]);
index++;
}
}
*/
private void createPortraits() { private void createPortraits() {
String category = ""; String category = "";
+3 -1
View File
@@ -1,4 +1,6 @@
public class Intelligence extends Stats { import java.io.Serializable;
public class Intelligence extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
+63 -1
View File
@@ -1,2 +1,64 @@
public class LoadCharacterPanel { import javax.swing.*;
import java.awt.*;
import java.util.*;
public class LoadCharacterPanel extends JPanel implements AppTheme {
private ArrayList<DefaultButton> savedCharacters;
public LoadCharacterPanel(JPanel nav, ArrayList<DefaultButton> savedCharacters) {
super();
panelSetup();
this.savedCharacters = savedCharacters;
createMasterPanel();
add(nav, BorderLayout.SOUTH);
}
private void panelSetup() {
setBackground(lightBrown);
setLayout(new BorderLayout(0, 0));
}
private void createMasterPanel() {
JLabel title = new JLabel("Load a Character");
title.setHorizontalAlignment(SwingConstants.CENTER);
title.setFont(headerFont);
title.setForeground(darkestBrown);
JPanel panel = new JPanel();
panel.setOpaque(false);
panel.setLayout(null);
//panel.add(buttonPanel());
// TODO: Need to implement.
//panel.add(portraitPanel());
add(buttonPanel(), BorderLayout.NORTH);
}
private JPanel buttonPanel() {
JPanel panel = new JPanel(new GridLayout(savedCharacters.size(), 1, 0, 0));
panel.setOpaque(false);
panel.setBackground(lightBrown);
for(int i = 0; i < savedCharacters.size(); i++) {
panel.add(savedCharacters.get(i));
}
return panel;
}
} }
-2
View File
@@ -1,2 +0,0 @@
public class PreviewCharacterSheet {
}
+3 -1
View File
@@ -1,4 +1,6 @@
public class Strength extends Stats { import java.io.Serializable;
public class Strength extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
+3 -1
View File
@@ -1,4 +1,6 @@
public class Wisdom extends Stats { import java.io.Serializable;
public class Wisdom extends Stats implements Serializable {
private int abilityScore; private int abilityScore;
private int abilityScoreModifier; private int abilityScoreModifier;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.