LevelUpSpellPanel.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package org.leumasjaffe.charsheet.view.level;
  2. import javax.swing.JPanel;
  3. import org.jdesktop.swingx.VerticalLayout;
  4. import org.leumasjaffe.charsheet.model.magic.DDSpell;
  5. import org.leumasjaffe.charsheet.model.observable.BoolGate;
  6. import org.leumasjaffe.charsheet.model.observable.IntValue;
  7. import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel;
  8. import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel.Info;
  9. import org.leumasjaffe.observer.ObservableListener;
  10. import org.leumasjaffe.observer.ObserverDispatch;
  11. import lombok.AccessLevel;
  12. import lombok.Getter;
  13. import lombok.experimental.FieldDefaults;
  14. import lombok.experimental.NonFinal;
  15. import java.awt.GridBagLayout;
  16. import java.util.ArrayList;
  17. import java.util.Collection;
  18. import java.util.Collections;
  19. import java.util.LinkedHashSet;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.TreeMap;
  23. import javax.swing.JScrollPane;
  24. import java.awt.GridBagConstraints;
  25. @SuppressWarnings("serial")
  26. @FieldDefaults(level=AccessLevel.PUBLIC, makeFinal=true)
  27. class LevelUpSpellPanel extends JPanel {
  28. public static interface SpellPicker {
  29. public List<List<Integer>> getSpellCounts(SelectSpellsPanel.Info info);
  30. public Collection<DDSpell> getAvailableSpells(SelectSpellsPanel.Info info, int i);
  31. }
  32. public static enum SpellPickType implements SpellPicker {
  33. LEARN {
  34. @Override
  35. public List<List<Integer>> getSpellCounts(SelectSpellsPanel.Info info) {
  36. return info.dclass.getProto().getSpells().get().getKnown();
  37. }
  38. @Override
  39. public Collection<DDSpell> getAvailableSpells(Info info, int i) {
  40. Collection<DDSpell> spells = new ArrayList<>(info.dclass.getProto().getSpellList(i));
  41. spells.removeAll(info.dclass.getSpellBook().get().spellsKnownAtLevel(i));
  42. return spells;
  43. }
  44. }, PREPARE {
  45. @Override
  46. public List<List<Integer>> getSpellCounts(SelectSpellsPanel.Info info) {
  47. // TODO: Bonus spells for high ability scores
  48. return info.dclass.getProto().getSpells().get().getPerDay();
  49. }
  50. @Override
  51. public Collection<DDSpell> getAvailableSpells(Info info, int i) {
  52. return info.dclass.getSpellBook().get().spellsKnownAtLevel(i);
  53. }
  54. };
  55. }
  56. int[] ready = {0};
  57. @NonFinal int spellLevelsGrown = 0;
  58. int oldHighestSpellLevel, newHighestSpellLevel, toLevel;
  59. SpellPicker pick;
  60. SelectSpellsPanel.Info info;
  61. @Getter List<SelectSpellsPanel> panels;
  62. ObservableListener<LevelUpSpellPanel, BoolGate> allReady;
  63. public LevelUpSpellPanel(SpellPicker pick, SelectSpellsPanel.Info info,
  64. BoolGate.Handle readyCount) {
  65. this.pick = pick;
  66. this.info = info;
  67. this.toLevel = info.dclass.getLevel().value();
  68. newHighestSpellLevel = info.dclass.getHighestSpellLevel(toLevel);
  69. oldHighestSpellLevel = info.dclass.getHighestSpellLevel(toLevel-1);
  70. GridBagLayout gridBagLayout = new GridBagLayout();
  71. gridBagLayout.columnWidths = new int[]{0, 0};
  72. gridBagLayout.rowHeights = new int[]{0, 0};
  73. gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE};
  74. gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE};
  75. setLayout(gridBagLayout);
  76. JScrollPane scrollPane = new JScrollPane();
  77. GridBagConstraints gbc_scrollPane = new GridBagConstraints();
  78. gbc_scrollPane.fill = GridBagConstraints.BOTH;
  79. gbc_scrollPane.gridx = 0;
  80. gbc_scrollPane.gridy = 0;
  81. add(scrollPane, gbc_scrollPane);
  82. JPanel panel = new JPanel(new VerticalLayout(5));
  83. scrollPane.setViewportView(panel);
  84. panels = new ArrayList<>();
  85. final IntValue val = getSharedAllowedSlots(info);
  86. final Map<Integer, Integer> spells = getNewSpells(val);
  87. final int sharedSlots = val.value();
  88. BoolGate gate = new BoolGate(newHighestSpellLevel);
  89. for (int i = 0; i < newHighestSpellLevel; ++i) {
  90. if (spells.get(i) < 0) { gate.set(i, true); panels.add(null); continue; }
  91. ++spellLevelsGrown;
  92. SelectSpellsPanel lvl = new SelectSpellsPanel(info, gate.handle(i), i,
  93. new LinkedHashSet<>(), Math.max(spells.get(i), sharedSlots),
  94. pick.getAvailableSpells(info, i),
  95. pick != SpellPickType.LEARN, val);
  96. panels.add(lvl);
  97. panel.add(lvl);
  98. }
  99. allReady = new ObservableListener<>(this, (c, v) -> {
  100. readyCount.set(this, v.all());
  101. });
  102. allReady.setObserved(gate);
  103. }
  104. private Map<Integer, Integer> getNewSpells(IntValue sharedSpellCountLimit) {
  105. final Map<Integer, Integer> map = new TreeMap<>();
  106. final List<List<Integer>> spellList = pick.getSpellCounts(info);
  107. final List<Integer> spellsAtPreviousLevel = toLevel == 1 ? Collections.emptyList() :
  108. spellList.get(toLevel-2);
  109. final List<Integer> spellsAtCurrentLevel = spellList.get(toLevel-1);
  110. for (int i = 0; i < newHighestSpellLevel; ++i) {
  111. map.put(i, diff(spellsAtCurrentLevel, spellsAtPreviousLevel, i,
  112. isNewSpellCircle(i)));
  113. }
  114. if (!map.isEmpty()) sharedSpellCountLimit.value(-1);
  115. return map;
  116. }
  117. private IntValue getSharedAllowedSlots(Info info) {
  118. return info.dclass.getSpellBook().get().getSharedAllowedSlots();
  119. }
  120. private boolean isNewSpellCircle(int i) {
  121. return i == (newHighestSpellLevel - 1) && oldHighestSpellLevel != newHighestSpellLevel;
  122. }
  123. private int diff(List<Integer> current, List<Integer> previous, int level, boolean newSpellLevel) {
  124. if (current.size() <= level) return 0;
  125. else if (newSpellLevel || previous.size() <= level) return current.get(level);
  126. else return current.get(level) - previous.get(level);
  127. }
  128. @Override
  129. public void removeNotify() {
  130. ObserverDispatch.unsubscribeAll(allReady);
  131. }
  132. }