Pārlūkot izejas kodu

Adding the ability to increase skill ranks on level up.
Currently, this system does not apply the skill change.

Sam Jaffe 8 gadi atpakaļ
vecāks
revīzija
7625c62cf2

+ 1 - 0
resources/classes/Bard.json

@@ -14,6 +14,7 @@
     ],
     []
   ],
+  "skillPoints":6,
   "skills":[
     "Appraise",
     "Balance",

+ 1 - 0
resources/classes/Cleric.json

@@ -11,6 +11,7 @@
       }
     ]
   ],
+  "skillPoints":2,
   "skills":[
     "Concentration",
     "Craft (*)",

+ 4 - 0
src/org/leumasjaffe/charsheet/model/DDCharacterClass.java

@@ -48,6 +48,10 @@ public class DDCharacterClass {
 	public String toString() {
 		return getName() + " " + getLevel();
 	}
+	
+	public int getSkillPoints() {
+		return name.base.getSkillPoints();
+	}
 
 	public int getBab() {
 		return name.base.getBab().getBonus(level);

+ 1 - 0
src/org/leumasjaffe/charsheet/model/DDClass.java

@@ -24,6 +24,7 @@ import lombok.experimental.FieldDefaults;
 public class DDClass {
 	@NonNull String name;
 	
+	int skillPoints;
 	@NonNull AttackQuality bab;
 	@NonNull SaveQuality fort;
 	@NonNull SaveQuality ref;

+ 7 - 1
src/org/leumasjaffe/charsheet/view/D20Sheet.java

@@ -21,6 +21,7 @@ import javax.swing.JMenuItem;
 import javax.swing.KeyStroke;
 
 import org.leumasjaffe.charsheet.model.DDCharacter;
+import org.leumasjaffe.charsheet.view.dev.DeveloperMenu;
 
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowEvent;
@@ -45,6 +46,7 @@ public class D20Sheet extends JFrame {
 	JPanel abilitiesTab;
 	SkillTab skillTab;
 	EquipmentTab equipmentTab;
+	private DeveloperMenu developerMenu;
 	
 	public D20Sheet() {
 		// Set up local state variables
@@ -99,7 +101,10 @@ public class D20Sheet extends JFrame {
 		mntmExit.addActionListener( e -> { this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } );
 		mntmExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_MASK));
 		mnFile.add(mntmExit);
-
+		
+		developerMenu = new DeveloperMenu();
+		menuBar.add(developerMenu);
+		
 		// Set up post-GUI dependencies
 		setModel(model);
 	}
@@ -141,6 +146,7 @@ public class D20Sheet extends JFrame {
 		model.getClasses().stream().forEach(cc -> classTabs.add(new ClassTab(cc)));
 		equipmentTab.setModel(model);
 		skillTab.setModel(model);
+		developerMenu.setModel(model);
 		
 		reorderTabs();
 	}

+ 1 - 2
src/org/leumasjaffe/charsheet/view/SkillTab.java

@@ -127,8 +127,7 @@ public class SkillTab extends JPanel {
 	public void setModel(final DDCharacter model) {
 		// TODO (sjaffe): Observables
 		skillPanel.removeAll();
-		int[] totalPoints = new int[1];
-		totalPoints[0] = 0;
+		int[] totalPoints = {0};
 		final DDSkills skills = model.getSkills();
 		skills.getSkills().stream().forEach( skill -> {
 			skillPanel.add(new SkillLine(model, skill));

+ 45 - 0
src/org/leumasjaffe/charsheet/view/dev/DeveloperMenu.java

@@ -0,0 +1,45 @@
+package org.leumasjaffe.charsheet.view.dev;
+
+import java.util.stream.Collectors;
+
+import javax.swing.JDialog;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+
+import org.leumasjaffe.charsheet.model.DDCharacter;
+import org.leumasjaffe.charsheet.model.DDCharacterClass;
+import org.leumasjaffe.charsheet.view.skills.SkillLevelUpDialogue;
+
+public class DeveloperMenu extends JMenu {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	DDCharacter[] model = { null };
+	
+	public DeveloperMenu() {
+		super("Developer");
+		JMenuItem mntmLevelUp = new JMenuItem("Level Up - Skill");
+		mntmLevelUp.addActionListener( e -> {
+			Object[] choices = model[0].getClasses().stream().map(DDCharacterClass::getName).collect(Collectors.toList()).toArray();
+			String clazz = (String) JOptionPane.showInputDialog(this.getParent(), "Which Class is Leveling Up?", "Level Up - Skill", 
+					JOptionPane.QUESTION_MESSAGE, null, choices, choices[0]);
+			if (clazz != null) {
+				final JDialog dialog = new JDialog();
+				dialog.setTitle("Level Up - Skill Allocation");
+				dialog.setModal(true);
+				dialog.setSize(510, 600);
+
+				dialog.setContentPane(new SkillLevelUpDialogue(model[0], model[0].getClasses().stream().filter(c -> c.getName().equals(clazz)).findFirst().get()));
+				dialog.setVisible(true);
+				dialog.pack();
+			}
+		});
+		add(mntmLevelUp);
+	}
+	
+	public void setModel(DDCharacter model) {
+		this.model[0] = model;
+	}
+}

+ 111 - 0
src/org/leumasjaffe/charsheet/view/skills/SkillLevelUpDialogue.java

@@ -0,0 +1,111 @@
+package org.leumasjaffe.charsheet.view.skills;
+
+import javax.swing.JPanel;
+
+import lombok.AccessLevel;
+import lombok.experimental.FieldDefaults;
+import java.awt.GridBagLayout;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+
+import org.jdesktop.swingx.VerticalLayout;
+import org.leumasjaffe.charsheet.model.Ability;
+import org.leumasjaffe.charsheet.model.DDCharacter;
+import org.leumasjaffe.charsheet.model.DDCharacterClass;
+import org.leumasjaffe.charsheet.model.observable.IntValue;
+import org.leumasjaffe.charsheet.model.skill.DDSkills;
+import org.leumasjaffe.observer.ObservableListener;
+
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import javax.swing.JLabel;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import java.awt.Dimension;
+
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+public class SkillLevelUpDialogue extends JPanel {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
+	public SkillLevelUpDialogue(final DDCharacter chara, final DDCharacterClass cclass) {
+		final IntValue pointsAvaliable = new IntValue(Math.max(1, cclass.getSkillPoints() + Ability.modifier(chara.getAbilities().getBase().getInt().value())));
+		
+		GridBagLayout gridBagLayout = new GridBagLayout();
+		gridBagLayout.columnWidths = new int[]{0, 0};
+		gridBagLayout.rowHeights = new int[]{0, 0, 0};
+		gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE};
+		gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
+		setLayout(gridBagLayout);
+		
+		JPanel panel = new JPanel();
+		GridBagConstraints gbc_panel = new GridBagConstraints();
+		gbc_panel.insets = new Insets(0, 0, 5, 0);
+		gbc_panel.fill = GridBagConstraints.HORIZONTAL;
+		gbc_panel.gridx = 0;
+		gbc_panel.gridy = 0;
+		add(panel, gbc_panel);
+		GridBagLayout gbl_panel = new GridBagLayout();
+		gbl_panel.columnWidths = new int[]{0, 0, 0, 0};
+		gbl_panel.rowHeights = new int[]{0, 0};
+		gbl_panel.columnWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE};
+		gbl_panel.rowWeights = new double[]{0.0, Double.MIN_VALUE};
+		panel.setLayout(gbl_panel);
+		
+		JLabel lblPointsRemaining = new JLabel("Points Remaining:");
+		GridBagConstraints gbc_lblPointsRemaining = new GridBagConstraints();
+		gbc_lblPointsRemaining.insets = new Insets(0, 0, 0, 5);
+		gbc_lblPointsRemaining.anchor = GridBagConstraints.EAST;
+		gbc_lblPointsRemaining.gridx = 0;
+		gbc_lblPointsRemaining.gridy = 0;
+		panel.add(lblPointsRemaining, gbc_lblPointsRemaining);
+		
+		JTextField pointsRemaining = new JTextField();
+		pointsRemaining.setEditable(false);
+		GridBagConstraints gbc_pointsRemaining = new GridBagConstraints();
+		gbc_pointsRemaining.insets = new Insets(0, 0, 0, 5);
+		gbc_pointsRemaining.fill = GridBagConstraints.HORIZONTAL;
+		gbc_pointsRemaining.gridx = 1;
+		gbc_pointsRemaining.gridy = 0;
+		panel.add(pointsRemaining, gbc_pointsRemaining);
+		pointsRemaining.setColumns(10);
+		
+		JScrollPane scrollPane = new JScrollPane();
+		GridBagConstraints gbc_scrollPane = new GridBagConstraints();
+		gbc_scrollPane.fill = GridBagConstraints.BOTH;
+		gbc_scrollPane.gridx = 0;
+		gbc_scrollPane.gridy = 1;
+		add(scrollPane, gbc_scrollPane);
+		
+		JPanel skillPanel = new JPanel();
+		skillPanel.setMinimumSize(new Dimension(300, 200));
+		scrollPane.setViewportView(skillPanel);
+		skillPanel.setLayout(new VerticalLayout());
+		
+		JButton btnSubmitSkillChange = new JButton("Submit Skill Change");
+		btnSubmitSkillChange.setEnabled(false);
+		GridBagConstraints gbc_btnSubmitSkillChange = new GridBagConstraints();
+		gbc_btnSubmitSkillChange.gridx = 2;
+		gbc_btnSubmitSkillChange.gridy = 0;
+		panel.add(btnSubmitSkillChange, gbc_btnSubmitSkillChange);
+		
+		final DDSkills skills = chara.getSkills();
+		skills.getSkills().stream().forEach( skill -> {
+			skillPanel.add(new SkillLevelUpLine(chara, cclass, skill, pointsAvaliable));
+		});
+		
+		ObservableListener<JTextField, IntValue> purchaseListener = new ObservableListener<>(pointsRemaining, (c, v) -> {
+			btnSubmitSkillChange.setEnabled(v.value() == 0);
+			c.setText(Integer.toString(v.value()));
+		});
+		purchaseListener.setObserved(pointsAvaliable);
+		
+		btnSubmitSkillChange.addActionListener(e -> {
+			((JDialog) this.getParent().getParent().getParent()).dispose();
+		});
+	}
+	
+}

+ 235 - 0
src/org/leumasjaffe/charsheet/view/skills/SkillLevelUpLine.java

@@ -0,0 +1,235 @@
+package org.leumasjaffe.charsheet.view.skills;
+
+import javax.swing.JPanel;
+
+import org.leumasjaffe.charsheet.model.Ability;
+import org.leumasjaffe.charsheet.model.DDCharacter;
+import org.leumasjaffe.charsheet.model.DDCharacterClass;
+import org.leumasjaffe.charsheet.model.observable.IntValue;
+import org.leumasjaffe.charsheet.model.skill.DDSkill;
+import org.leumasjaffe.charsheet.util.StringHelper;
+import org.leumasjaffe.observer.IndirectObservableListener;
+import org.leumasjaffe.observer.Observable;
+import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
+
+import lombok.AccessLevel;
+import lombok.experimental.FieldDefaults;
+
+import java.awt.GridBagLayout;
+import javax.swing.JCheckBox;
+import java.awt.GridBagConstraints;
+import javax.swing.JLabel;
+import java.awt.Insets;
+import java.awt.Dimension;
+import javax.swing.JTextField;
+import java.awt.Color;
+import javax.swing.border.MatteBorder;
+import javax.swing.SwingConstants;
+import java.awt.Component;
+import javax.swing.Box;
+import javax.swing.JButton;
+import java.awt.Font;
+
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+public class SkillLevelUpLine extends JPanel {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	ObservableListener<JTextField, IntValue> modifierListener;
+	IndirectObservableListener<JTextField, DDCharacter> totalListener;
+
+	public SkillLevelUpLine(final DDCharacter chara, final DDCharacterClass cclass, final DDSkill skill, IntValue pointsAvaliable) {
+		final IntValue current = new IntValue(0);
+		final int pointsPerRank = cclass.isClassSkill(skill.getName()) ? 1 : 2;
+		final int startingRanks = skill.getRanks();
+		
+		setBorder(new MatteBorder(0, 0, 1, 0, (Color) new Color(0, 0, 0)));
+		setPreferredSize(new Dimension(475, 22));
+		GridBagLayout gridBagLayout = new GridBagLayout();
+		gridBagLayout.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+		gridBagLayout.rowHeights = new int[]{0, 0};
+		gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+		gridBagLayout.rowWeights = new double[]{0.0, Double.MIN_VALUE};
+		setLayout(gridBagLayout);
+		
+		JCheckBox checkBoxIsClassSkill = new JCheckBox("");
+		checkBoxIsClassSkill.setToolTipText("Class Skill?");
+		checkBoxIsClassSkill.setSelected(cclass.isClassSkill(skill.getName()));
+		checkBoxIsClassSkill.setEnabled(false);
+		GridBagConstraints gbc_checkBoxIsClassSkill = new GridBagConstraints();
+		gbc_checkBoxIsClassSkill.insets = new Insets(1, 0, 0, 5);
+		gbc_checkBoxIsClassSkill.gridx = 0;
+		gbc_checkBoxIsClassSkill.gridy = 0;
+		add(checkBoxIsClassSkill, gbc_checkBoxIsClassSkill);
+		
+		JLabel lblName = new JLabel(skill.getName());
+		lblName.setMaximumSize(new Dimension(150, 14));
+		lblName.setMinimumSize(new Dimension(150, 14));
+		lblName.setPreferredSize(new Dimension(150, 14));
+		GridBagConstraints gbc_lblName = new GridBagConstraints();
+		gbc_lblName.fill = GridBagConstraints.HORIZONTAL;
+		gbc_lblName.insets = new Insets(1, 0, 0, 5);
+		gbc_lblName.gridx = 1;
+		gbc_lblName.gridy = 0;
+		add(lblName, gbc_lblName);
+		
+		JLabel lblAbil = new JLabel(skill.getAbility());
+		lblAbil.setMaximumSize(new Dimension(30, 14));
+		lblAbil.setMinimumSize(new Dimension(30, 14));
+		lblAbil.setPreferredSize(new Dimension(30, 14));
+		GridBagConstraints gbc_lblAbil = new GridBagConstraints();
+		gbc_lblAbil.insets = new Insets(1, 0, 0, 5);
+		gbc_lblAbil.anchor = GridBagConstraints.EAST;
+		gbc_lblAbil.gridx = 2;
+		gbc_lblAbil.gridy = 0;
+		add(lblAbil, gbc_lblAbil);
+		
+		JTextField total = new JTextField();
+		total.setToolTipText("Skill Modifier");
+		total.setHorizontalAlignment(SwingConstants.CENTER);
+		total.setEditable(false);
+		total.setMinimumSize(new Dimension(30, 20));
+		total.setMaximumSize(new Dimension(30, 20));
+		total.setPreferredSize(new Dimension(30, 20));
+		GridBagConstraints gbc_total = new GridBagConstraints();
+		gbc_total.insets = new Insets(1, 0, 0, 5);
+		gbc_total.fill = GridBagConstraints.HORIZONTAL;
+		gbc_total.gridx = 3;
+		gbc_total.gridy = 0;
+		add(total, gbc_total);
+		total.setColumns(10);
+		
+		JLabel label = new JLabel("=");
+		GridBagConstraints gbc_label = new GridBagConstraints();
+		gbc_label.anchor = GridBagConstraints.EAST;
+		gbc_label.insets = new Insets(1, 0, 0, 5);
+		gbc_label.gridx = 4;
+		gbc_label.gridy = 0;
+		add(label, gbc_label);
+		
+		JTextField modifier = new JTextField();
+		modifier.setToolTipText("Ability Modifier");
+		modifier.setHorizontalAlignment(SwingConstants.CENTER);
+		modifier.setEditable(false);
+		modifier.setMinimumSize(new Dimension(30, 20));
+		modifier.setMaximumSize(new Dimension(30, 20));
+		modifier.setPreferredSize(new Dimension(30, 20));
+		GridBagConstraints gbc_modifier = new GridBagConstraints();
+		gbc_modifier.insets = new Insets(1, 0, 0, 5);
+		gbc_modifier.fill = GridBagConstraints.HORIZONTAL;
+		gbc_modifier.gridx = 5;
+		gbc_modifier.gridy = 0;
+		add(modifier, gbc_modifier);
+		modifier.setColumns(10);
+		
+		JLabel label_1 = new JLabel("+");
+		GridBagConstraints gbc_label_1 = new GridBagConstraints();
+		gbc_label_1.anchor = GridBagConstraints.EAST;
+		gbc_label_1.insets = new Insets(1, 0, 0, 5);
+		gbc_label_1.gridx = 6;
+		gbc_label_1.gridy = 0;
+		add(label_1, gbc_label_1);
+		
+		JTextField ranks = new JTextField(StringHelper.toString(skill.getRanks()));
+		ranks.setToolTipText("Ranks");
+		ranks.setHorizontalAlignment(SwingConstants.CENTER);
+		ranks.setEditable(false);
+		ranks.setMinimumSize(new Dimension(30, 20));
+		ranks.setMaximumSize(new Dimension(30, 20));
+		ranks.setPreferredSize(new Dimension(30, 20));
+		GridBagConstraints gbc_ranks = new GridBagConstraints();
+		gbc_ranks.insets = new Insets(1, 0, 0, 5);
+		gbc_ranks.fill = GridBagConstraints.HORIZONTAL;
+		gbc_ranks.gridx = 7;
+		gbc_ranks.gridy = 0;
+		add(ranks, gbc_ranks);
+		ranks.setColumns(10);
+		
+		Component horizontalStrut = Box.createHorizontalStrut(20);
+		GridBagConstraints gbc_horizontalStrut = new GridBagConstraints();
+		gbc_horizontalStrut.insets = new Insets(0, 0, 0, 5);
+		gbc_horizontalStrut.gridx = 8;
+		gbc_horizontalStrut.gridy = 0;
+		add(horizontalStrut, gbc_horizontalStrut);
+		
+		JButton plus = new JButton("+");
+		plus.setMargin(new Insets(2, 2, 2, 2));
+		plus.setFont(new Font("Tahoma", Font.PLAIN, 8));
+		plus.setPreferredSize(new Dimension(30, 19));
+		plus.setMinimumSize(new Dimension(30, 19));
+		GridBagConstraints gbc_plus = new GridBagConstraints();
+		gbc_plus.insets = new Insets(0, 0, 1, 5);
+		gbc_plus.gridx = 9;
+		gbc_plus.gridy = 0;
+		add(plus, gbc_plus);
+		
+		JButton minus = new JButton("-");
+		minus.setMargin(new Insets(2, 2, 2, 2));
+		minus.setFont(new Font("Tahoma", Font.PLAIN, 8));
+		minus.setMinimumSize(new Dimension(30, 19));
+		minus.setPreferredSize(new Dimension(30, 19));
+		GridBagConstraints gbc_minus = new GridBagConstraints();
+		gbc_minus.insets = new Insets(0, 0, 1, 5);
+		gbc_minus.gridx = 10;
+		gbc_minus.gridy = 0;
+		add(minus, gbc_minus);
+		
+		JTextField points = new JTextField();
+		points.setMinimumSize(new Dimension(30, 20));
+		points.setText("0");
+		points.setEditable(false);
+		GridBagConstraints gbc_points = new GridBagConstraints();
+		gbc_points.gridx = 11;
+		gbc_points.gridy = 0;
+		add(points, gbc_points);
+		points.setColumns(10);
+		
+		plus.addActionListener((e) -> {
+			if (pointsAvaliable.value() >= pointsPerRank) {
+				pointsAvaliable.value(pointsAvaliable.value() - pointsPerRank);
+				current.value(current.value() + 1);
+				points.setText(Integer.toString(current.value()));
+				ObserverDispatch.notifySubscribers(pointsAvaliable, this);
+			} else {
+				// TODO warning
+			}
+		});
+		minus.addActionListener((e) -> {
+			if (current.value() > 0) {
+				pointsAvaliable.value(pointsAvaliable.value() + pointsPerRank);
+				current.value(current.value() - 1);
+				points.setText(Integer.toString(current.value()));
+				ObserverDispatch.notifySubscribers(pointsAvaliable, this);
+			} else {
+				// TODO warning
+			}
+		});
+
+		if ( skill.getAbility().isEmpty() ) {
+			totalListener = new IndirectObservableListener<>(total,
+					(c, v) -> {
+						c.setText(StringHelper.toString(skill.getRanks()));
+					});
+			modifierListener = null;
+			totalListener.setObserved(chara, new Observable());
+		} else {
+			totalListener = new IndirectObservableListener<>(total,
+					(c, v) -> {
+						final float skillRanks = skill.getRanks();
+						final int mod = Ability.modifier(Ability.fields.get(skill.getAbility())
+								.apply(chara.getAbilities().getBase()).value());
+						c.setText(StringHelper.toString(skillRanks + mod));
+					});
+			modifierListener = new ObservableListener<>(modifier, 
+					( c, v ) -> c.setText(StringHelper.toString(Ability.modifier(v.value()))));
+			
+			final IntValue abilScore = 	Ability.fields.get(skill.getAbility())
+					.apply(chara.getAbilities().getBase());
+			totalListener.setObserved(chara, abilScore);
+			modifierListener.setObserved(abilScore);
+		}
+	}
+	
+}