From fb8dcb9fb4e3d10d12912846401ffb83db266d55 Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 14 Apr 2017 15:52:32 +0200 Subject: [PATCH] v0.6.1! Rebuilt completely the Quest editor. Each quest stage has its own backlinks now. Quest log entries and dialogue replies are now translatable too. Multiple minor UI improvements (notably multiline text area are now taller, and rewards and requirements appear more clearly in the dialogue tree view). --- ATCS_JAR.jardesc | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- .../rpg/atcontentstudio/ATContentStudio.java | 2 +- .../rpg/atcontentstudio/model/Project.java | 10 + .../model/gamedata/Dialogue.java | 18 +- .../atcontentstudio/model/gamedata/Quest.java | 50 +-- .../model/gamedata/QuestStage.java | 103 +++++ .../model/gamedata/Requirement.java | 12 + .../gpl/rpg/atcontentstudio/ui/Editor.java | 145 +++++- .../ui/gamedataeditors/DialogueEditor.java | 41 +- .../ui/gamedataeditors/JSONElementEditor.java | 23 +- .../ui/gamedataeditors/QuestEditor.java | 424 ++++++++---------- .../dialoguetree/DialogueGraphView.java | 44 +- .../atcontentstudio/ui/map/TMXMapEditor.java | 31 +- 14 files changed, 599 insertions(+), 308 deletions(-) create mode 100644 src/com/gpl/rpg/atcontentstudio/model/gamedata/QuestStage.java diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index a14050b..167a5a5 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index a0929a9..52246c5 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.0" +!define VERSION "0.6.1" !define TRAINER_VERSION "0.1.3" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index 45c4f4b..c6da36a 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -24,7 +24,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.0"; + public static final String APP_VERSION = "v0.6.1"; public static boolean STARTED = false; public static StudioFrame frame = null; diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 4badae0..dd512b9 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -39,6 +39,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet; import com.gpl.rpg.atcontentstudio.model.maps.Worldmap; @@ -758,6 +759,15 @@ public class Project implements ProjectTreeNode, Serializable { } else { if (type == GameSource.Type.source) { JSONElement clone = (JSONElement) node.clone(); + if (node instanceof Quest) { + for (QuestStage oldStage : ((Quest) node).stages) { + QuestStage newStage = ((Quest) clone).getStage(oldStage.progress); + for (GameDataElement backlink : oldStage.getBacklinks()) { + backlink.elementChanged(oldStage, newStage); + } + oldStage.getBacklinks().clear(); + } + } for (GameDataElement backlink : node.getBacklinks()) { backlink.elementChanged(node, clone); } diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java index 59ffaa2..7cb382f 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java @@ -265,6 +265,12 @@ public class Dialogue extends JSONElement { break; case questProgress: reward.reward_obj = proj.getQuest(reward.reward_obj_id); + if (reward.reward_obj != null && reward.reward_value != null) { + QuestStage stage = ((Quest)reward.reward_obj).getStage(reward.reward_value); + if (stage != null) { + stage.addBacklink(this); + } + } break; case skillIncrease: //Nothing to do (yet ?). @@ -361,11 +367,7 @@ public class Dialogue extends JSONElement { } if (r.requirements != null) { for (Requirement req : r.requirements) { - if (req.required_obj == oldOne) { - oldOne.removeBacklink(this); - req.required_obj = newOne; - if (newOne != null) newOne.addBacklink(this); - } + req.elementChanged(oldOne, newOne); } } } @@ -377,6 +379,12 @@ public class Dialogue extends JSONElement { r.reward_obj = newOne; if (newOne != null) newOne.addBacklink(this); } + if (oldOne instanceof QuestStage) { + if (r.reward_obj != null && r.reward_obj.equals(oldOne.parent) && r.reward_value != null && r.reward_value.equals(((QuestStage) oldOne).progress)) { + oldOne.removeBacklink((GameDataElement) this); + if (newOne != null) newOne.addBacklink((GameDataElement) this); + } + } } } } diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java index 3b71ccf..c1e683a 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java @@ -30,22 +30,6 @@ public class Quest extends JSONElement { public Integer visible_in_log = null; public List stages = null; - public static class QuestStage implements Cloneable { - public Integer progress = null; - public String log_text = null; - public Integer exp_reward = null; - public Integer finishes_quest = null; - - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return null; - } - } - @Override public String getDesc() { return (needsSaving() ? "*" : "")+name+" ("+id+")"; @@ -105,6 +89,8 @@ public class Quest extends JSONElement { Quest quest = new Quest(); quest.id = (String) questJson.get("id"); quest.name = (String) questJson.get("name"); + //Quests have to be parsed to have their stages initialized. + quest.parse(questJson); return quest; } @@ -117,15 +103,12 @@ public class Quest extends JSONElement { this.stages = new ArrayList(); for (Object questStageJsonObj : questStagesJson) { Map questStageJson = (Map)questStageJsonObj; - QuestStage questStage = new QuestStage(); - questStage.progress = JSONElement.getInteger((Number) questStageJson.get("progress")); - questStage.log_text = (String) questStageJson.get("logText"); - questStage.exp_reward = JSONElement.getInteger((Number) questStageJson.get("rewardExperience")); - questStage.finishes_quest = JSONElement.getInteger((Number) questStageJson.get("finishesQuest")); + QuestStage questStage = new QuestStage(this); + questStage.parse(questStageJson); this.stages.add(questStage); } } - + this.state = State.parsed; } @Override @@ -142,6 +125,9 @@ public class Quest extends JSONElement { return; } + for (QuestStage stage : stages) { + stage.link(); + } //Nothing to link to :D this.state = State.linked; } @@ -164,9 +150,9 @@ public class Quest extends JSONElement { clone.name = this.name; clone.visible_in_log = this.visible_in_log; if (this.stages != null) { - clone.stages = new ArrayList(); + clone.stages = new ArrayList(); for (QuestStage stage : this.stages){ - clone.stages.add((QuestStage) stage.clone()); + clone.stages.add((QuestStage) stage.clone(clone)); } } return clone; @@ -188,12 +174,7 @@ public class Quest extends JSONElement { List stagesJson = new ArrayList(); questJson.put("stages", stagesJson); for (QuestStage stage : this.stages) { - Map stageJson = new LinkedHashMap(); - stagesJson.add(stageJson); - if (stage.progress != null) stageJson.put("progress", stage.progress); - if (stage.log_text != null) stageJson.put("logText", stage.log_text); - if (stage.exp_reward != null) stageJson.put("rewardExperience", stage.exp_reward); - if (stage.finishes_quest != null) stageJson.put("finishesQuest", stage.finishes_quest); + stagesJson.add(stage.toJson()); } } return questJson; @@ -204,5 +185,14 @@ public class Quest extends JSONElement { public String getProjectFilename() { return "questlist_"+getProject().name+".json"; } + + public QuestStage getStage(Integer stageId) { + for (QuestStage stage : stages) { + if (stage.progress.equals(stageId)) { + return stage; + } + } + return null; + } } diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/QuestStage.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/QuestStage.java new file mode 100644 index 0000000..61baa85 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/QuestStage.java @@ -0,0 +1,103 @@ +package com.gpl.rpg.atcontentstudio.model.gamedata; + +import java.awt.Image; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.gpl.rpg.atcontentstudio.model.GameDataElement; +import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; + +public class QuestStage extends JSONElement { + + private static final long serialVersionUID = 8313645819951513431L; + + public Integer progress = null; + public String log_text = null; + public Integer exp_reward = null; + public Integer finishes_quest = null; + + public QuestStage(Quest parent){ + this.parent = parent; + } + + public QuestStage clone(Quest cloneParent) { + QuestStage clone = new QuestStage(cloneParent); + clone.progress = progress != null ? new Integer(progress) : null; + clone.log_text = log_text != null ? new String(log_text) : null; + clone.exp_reward = exp_reward != null ? new Integer(exp_reward) : null; + clone.finishes_quest = finishes_quest != null ? new Integer(finishes_quest) : null; + clone.id = this.id; + return clone; + } + + @SuppressWarnings("rawtypes") + @Override + public void parse(Map jsonObj) { + progress = JSONElement.getInteger((Number) jsonObj.get("progress")); + this.id = ((Quest)parent).id+":"+progress; + log_text = (String) jsonObj.get("logText"); + exp_reward = JSONElement.getInteger((Number) jsonObj.get("rewardExperience")); + finishes_quest = JSONElement.getInteger((Number) jsonObj.get("finishesQuest")); + state = State.parsed; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Map toJson() { + Map stageJson = new LinkedHashMap(); + if (progress != null) stageJson.put("progress", progress); + if (log_text != null) stageJson.put("logText", log_text); + if (exp_reward != null) stageJson.put("rewardExperience", exp_reward); + if (finishes_quest != null) stageJson.put("finishesQuest", finishes_quest); + return stageJson; + } + + @Override + public String getDesc() { + return progress+" - "+(exp_reward != null ? "["+exp_reward+"XP]" : "")+((finishes_quest != null) && (finishes_quest == 1) ? "[END]" : "")+log_text; + } + + @Override + public void link() { + if (this.state == State.created || this.state == State.modified || this.state == State.saved) { + //This type of state is unrelated to parsing/linking. + return; + } + if (this.state == State.init) { + //Not parsed yet. + this.parse(); + } else if (this.state == State.linked) { + //Already linked. + return; + } + + //Nothing to link to :D + this.state = State.linked; + } + + @Override + public void elementChanged(GameDataElement oldOne, GameDataElement newOne) { + // Nothing to link to. + } + + @Override + public String getProjectFilename() { + return ((Quest)parent).getProjectFilename(); + } + + @Override + public GameDataElement clone() { + return null; + } + + @Override + public Image getIcon() { + return DefaultIcons.getQuestIcon(); + } + + public Image getImage() { + return DefaultIcons.getQuestImage(); + } + + +} \ No newline at end of file diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java index a67392c..8294c64 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java @@ -112,6 +112,12 @@ public class Requirement extends JSONElement { case questLatestProgress: case questProgress: this.required_obj = proj.getQuest(required_obj_id); + if (this.required_obj != null && this.required_value != null) { + QuestStage stage = ((Quest)this.required_obj).getStage(this.required_value); + if (stage != null) { + stage.addBacklink((GameDataElement) this.parent); + } + } break; case consumedBonemeals: case skillLevel: @@ -150,6 +156,12 @@ public class Requirement extends JSONElement { this.required_obj = newOne; if (newOne != null) newOne.addBacklink((GameDataElement) this.parent); } + if (oldOne instanceof QuestStage) { + if (this.required_obj != null && this.required_obj.equals(oldOne.parent) && this.required_value != null && this.required_value.equals(((QuestStage) oldOne).progress)) { + oldOne.removeBacklink((GameDataElement) this.parent); + if (newOne != null) newOne.addBacklink((GameDataElement) this.parent); + } + } } @Override public String getProjectFilename() { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java index 6ae9ae0..8d885d5 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java @@ -39,6 +39,7 @@ import javax.swing.JSpinner.NumberEditor; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListModel; +import javax.swing.Scrollable; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -63,6 +64,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration; import com.jidesoft.swing.ComboBoxSearchable; @@ -118,7 +120,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener { public static void addTranslationPane(JPanel pane, final JTextComponent tfComponent, final String initialValue) {if (Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null) { JPanel labelPane = new JPanel(); - labelPane.setLayout(new JideBoxLayout(labelPane, JideBoxLayout.LINE_AXIS)); + labelPane.setLayout(new JideBoxLayout(labelPane, JideBoxLayout.LINE_AXIS, 6)); final JLabel translateLinkLabel = new JLabel(getWeblateLabelLink(initialValue)); labelPane.add(translateLinkLabel, JideBoxLayout.FIX); labelPane.add(new JLabel(" "), JideBoxLayout.FIX); @@ -270,6 +272,9 @@ public abstract class Editor extends JPanel implements ProjectElementListener { tfPane.add(tfLabel, JideBoxLayout.FIX); final JTextArea tfArea = new JTextArea(text); tfArea.setEditable(editable); + tfArea.setRows(2); + tfArea.setLineWrap(true); + tfArea.setWrapStyleWord(true); tfPane.add(new JScrollPane(tfArea), JideBoxLayout.VARY); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); tfPane.add(nullify, JideBoxLayout.FIX); @@ -644,8 +649,63 @@ public abstract class Editor extends JPanel implements ProjectElementListener { return gdeBox; } + public JComboBox addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, final JComboBox questSelectionBox) { + JPanel gdePane = new JPanel(); + gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6)); + JLabel gdeLabel = new JLabel(label); + gdePane.add(gdeLabel, JideBoxLayout.FIX); + + QuestStage initial = null; + if (quest != null) { + initial = quest.getStage(initialValue); + } + final QuestStageComboModel comboModel = new QuestStageComboModel(proj, initial, quest); + final JComboBox combo = new JComboBox(comboModel); + combo.setRenderer(new GDERenderer(false, writable)); + new ComboBoxSearchable(combo){ + @Override + protected String convertElementToString(Object object) { + if (object == null) return "none"; + else return ((GameDataElement)object).getDesc(); + } + }; + questSelectionBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (comboModel.selected != null) { + Editor.this.target.removeBacklink(comboModel.selected); + } + Quest newQuest = (Quest) questSelectionBox.getSelectedItem(); + comboModel.changeQuest(newQuest); + combo.revalidate(); + } + }); + combo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + listener.valueChanged(combo, comboModel.selected == null ? null : comboModel.selected.progress); + } + }); + + + + combo.setEnabled(writable); + gdePane.add(combo, JideBoxLayout.VARY); + + pane.add(gdePane, JideBoxLayout.FIX); + + return combo; + } + + + @SuppressWarnings({ "rawtypes", "unchecked" }) public JList addBacklinksList(JPanel pane, GameDataElement gde) { + return addBacklinksList(pane, gde, "Elements linking to this one"); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public JList addBacklinksList(JPanel pane, GameDataElement gde, String title) { final JList list = new JList(new GDEBacklinksListModel(gde)); list.addMouseListener(new MouseAdapter() { @Override @@ -666,7 +726,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener { } }); list.setCellRenderer(new GDERenderer(true, false)); - CollapsiblePanel colPane = new CollapsiblePanel("Elements linking to this one"); + CollapsiblePanel colPane = new CollapsiblePanel(title); colPane.setLayout(new JideBoxLayout(colPane, JideBoxLayout.PAGE_AXIS)); colPane.add(new JScrollPane(list), JideBoxLayout.FIX); colPane.add(new JPanel(), JideBoxLayout.FIX); @@ -744,9 +804,25 @@ public abstract class Editor extends JPanel implements ProjectElementListener { label.setText("None"+(writable ? ". Click on the button to create one." : "")); } else { if (includeType && ((GameDataElement)value).getDataType() != null) { - label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc()); + if (value instanceof QuestStage) { + String text = ((GameDataElement)value).getDesc(); + if (text.length() > 60) { + text = text.substring(0, 57)+"..."; + } + label.setText(((GameDataElement)value).getDataType().toString()+"/"+((Quest)((QuestStage)value).parent).id+":"+text); + } else { + label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc()); + } } else { - label.setText(((GameDataElement)value).getDesc()); + if (value instanceof QuestStage) { + String text = ((GameDataElement)value).getDesc(); + if (text.length() > 60) { + text = text.substring(0, 57)+"..."; + } + label.setText(text); + } else { + label.setText(((GameDataElement)value).getDesc()); + } } if (((GameDataElement)value).getIcon() == null) { Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc()); @@ -759,6 +835,65 @@ public abstract class Editor extends JPanel implements ProjectElementListener { } + public static class QuestStageComboModel extends AbstractListModel implements ComboBoxModel { + + private static final long serialVersionUID = -5854574666510314715L; + + public Project project; + public Quest currentQuest; + public QuestStage selected; + + public QuestStageComboModel(Project proj, QuestStage initial, Quest quest) { + this.project = proj; + this.currentQuest = quest; + this.selected = initial; + } + + @Override + public int getSize() { + if (currentQuest == null) return 1; + return currentQuest.stages.size()+1; + } + + @Override + public QuestStage getElementAt(int index) { + if (index == 0) { + return null; + } + return currentQuest.stages.get(index - 1); + } + + @SuppressWarnings("unchecked") + @Override + public void setSelectedItem(Object anItem) { + selected = (QuestStage) anItem; + } + + @Override + public Object getSelectedItem() { + return selected; + } + + public void itemAdded(QuestStage item, int index) { + fireIntervalAdded(this, index, index); + } + + public void itemRemoved(QuestStage item, int index) { + fireIntervalRemoved(this, index, index); + } + + public void changeQuest(Quest newQuest) { + int size = getSize(); + currentQuest = null; + selected = null; + fireIntervalRemoved(this, 1, size); + currentQuest = newQuest; + fireIntervalAdded(this, 1, getSize()); + } + + } + + public static class GDEBacklinksListModel implements ListModel { GameDataElement source; @@ -892,7 +1027,5 @@ public abstract class Editor extends JPanel implements ProjectElementListener { return null; } - - } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index 7a518f7..c86e3cd 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -43,6 +43,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist; import com.gpl.rpg.atcontentstudio.model.gamedata.Item; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.ui.BooleanBasedCheckBox; @@ -94,7 +95,7 @@ public class DialogueEditor extends JSONElementEditor { private JTextField rewardObjId; private JComboBox rewardObjIdCombo; private MyComboBox rewardObj; - private JSpinner rewardValue; + private JComponent rewardValue; private RepliesListModel repliesListModel; @SuppressWarnings("rawtypes") @@ -114,7 +115,7 @@ public class DialogueEditor extends JSONElementEditor { private JPanel requirementParamsPane; private MyComboBox requirementObj; private JTextField requirementObjId; - private JSpinner requirementValue; + private JComponent requirementValue; private BooleanBasedCheckBox requirementNegated; private DialogueGraphView dialogueGraphView; @@ -421,7 +422,7 @@ public class DialogueEditor extends JSONElementEditor { rewardObjId = null; rewardObjIdCombo = null; rewardObj = addQuestBox(pane, ((Dialogue)target).getProject(), "Quest: ", (Quest) reward.reward_obj, writable, listener); - rewardValue = addIntegerField(pane, "Step ID: ", reward.reward_value, false, writable, listener); + rewardValue = addQuestStageBox(pane, ((Dialogue)target).getProject(), "Quest stage: ", reward.reward_value, writable, listener, (Quest) reward.reward_obj, rewardObj); break; case skillIncrease: rewardMap = null; @@ -613,10 +614,10 @@ public class DialogueEditor extends JSONElementEditor { replyText = null; replyNextPhrase = addDialogueBox(pane, ((Dialogue)target).getProject(), "Next phrase: ", reply.next_phrase, writable, listener); } else if (Dialogue.Reply.KEY_PHRASE_ID.contains(reply.next_phrase_id)) { - replyText = addTextField(pane, "Reply text: ", reply.text, writable, listener); + replyText = addTranslatableTextField(pane, "Reply text: ", reply.text, writable, listener); replyNextPhrase = null; } else { - replyText = addTextField(pane, "Reply text: ", reply.text, writable, listener); + replyText = addTranslatableTextField(pane, "Reply text: ", reply.text, writable, listener); replyNextPhrase = addDialogueBox(pane, ((Dialogue)target).getProject(), "Next phrase: ", reply.next_phrase, writable, listener); } @@ -679,7 +680,7 @@ public class DialogueEditor extends JSONElementEditor { case questProgress: requirementObj = addQuestBox(pane, project, "Quest: ", (Quest) requirement.required_obj, writable, listener); requirementObjId = null; - requirementValue = addIntegerField(pane, "Quest stage: ", requirement.required_value, false, writable, listener); + requirementValue = addQuestStageBox(pane, project, "Quest stage: ", requirement.required_value, writable, listener, (Quest) requirement.required_obj, requirementObj); break; case skillLevel: requirementObj = null; @@ -1149,7 +1150,21 @@ public class DialogueEditor extends JSONElementEditor { } rewardsListModel.itemChanged(selectedReward); } else if (source == rewardValue) { + //Backlink removal to quest stages when selecting another quest are handled in the addQuestStageBox() method. Too complex too handle here + Quest quest = null; + QuestStage stage = null; + if (rewardValue instanceof JComboBox) { + quest = ((Quest)selectedReward.reward_obj); + if (quest != null && selectedReward.reward_value != null) { + stage = quest.getStage(selectedReward.reward_value); + if (stage != null) stage.removeBacklink(dialogue); + } + } selectedReward.reward_value = (Integer) value; + if (quest != null) { + stage = quest.getStage(selectedReward.reward_value); + if (stage != null) stage.addBacklink(dialogue); + } rewardsListModel.itemChanged(selectedReward); } else if (source == replyTypeCombo) { updateRepliesParamsEditorPane(repliesParamsPane, selectedReply, this); @@ -1190,7 +1205,21 @@ public class DialogueEditor extends JSONElementEditor { selectedRequirement.required_obj = null; requirementsListModel.itemChanged(selectedRequirement); } else if (source == requirementValue) { + //Backlink removal to quest stages when selecting another quest are handled in the addQuestStageBox() method. Too complex too handle here + Quest quest = null; + QuestStage stage = null; + if (requirementValue instanceof JComboBox) { + quest = ((Quest)selectedRequirement.required_obj); + if (quest != null && selectedRequirement.required_value != null) { + stage = quest.getStage(selectedRequirement.required_value); + if (stage != null) stage.removeBacklink(dialogue); + } + } selectedRequirement.required_value = (Integer) value; + if (quest != null) { + stage = quest.getStage(selectedRequirement.required_value); + if (stage != null) stage.addBacklink(dialogue); + } requirementsListModel.itemChanged(selectedRequirement); } else if (source == requirementNegated) { selectedRequirement.negated = (Boolean) value; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java index 96278bf..45b0e34 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java @@ -16,6 +16,7 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; @@ -29,6 +30,8 @@ import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; import com.gpl.rpg.atcontentstudio.model.SaveEvent; import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataCategory; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; +import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment; import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet; @@ -37,8 +40,11 @@ import com.gpl.rpg.atcontentstudio.ui.Editor; import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener; import com.gpl.rpg.atcontentstudio.ui.IdChangeImpactWizard; import com.gpl.rpg.atcontentstudio.ui.SaveItemsWizard; +import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel; +import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel.ScrollableSizeHint; import com.gpl.rpg.atcontentstudio.ui.sprites.SpriteChooser; import com.jidesoft.swing.JideBoxLayout; +import com.jidesoft.swing.JideScrollPane; import com.jidesoft.swing.JideTabbedPane; public abstract class JSONElementEditor extends Editor { @@ -65,7 +71,11 @@ public abstract class JSONElementEditor extends Editor { } public void addEditorTab(String id, JPanel editor) { - JScrollPane scroller = new JScrollPane(editor); + ScrollablePanel view = new ScrollablePanel(new BorderLayout()); + view.setScrollableWidth(ScrollableSizeHint.FIT); + view.setScrollableHeight(ScrollableSizeHint.STRETCH); + view.add(editor, BorderLayout.CENTER); + JScrollPane scroller = new JScrollPane(view, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scroller.getVerticalScrollBar().setUnitIncrement(16); editorTabsHolder.addTab(id, scroller); editorTabs.put(id, editor); @@ -178,8 +188,17 @@ public abstract class JSONElementEditor extends Editor { if (node.getParent() instanceof GameDataCategory) { ((GameDataCategory)node.getParent()).remove(node); node.save(); + GameDataElement newOne = proj.getGameDataElement(node.getClass(), node.id); + if (node instanceof Quest) { + for (QuestStage oldStage : ((Quest) node).stages) { + QuestStage newStage = newOne != null ? ((Quest) newOne).getStage(oldStage.progress) : null; + for (GameDataElement backlink : oldStage.getBacklinks()) { + backlink.elementChanged(oldStage, newStage); + } + } + } for (GameDataElement backlink : node.getBacklinks()) { - backlink.elementChanged(node, proj.getGameDataElement(node.getClass(), node.id)); + backlink.elementChanged(node, newOne); } } } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java index bfe20a0..4e416f5 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java @@ -1,6 +1,5 @@ package com.gpl.rpg.atcontentstudio.ui.gamedataeditors; -import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -8,27 +7,30 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTable; +import javax.swing.JSpinner; import javax.swing.JTextArea; import javax.swing.JTextField; -import javax.swing.UIManager; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableModel; import com.gpl.rpg.atcontentstudio.ATContentStudio; import com.gpl.rpg.atcontentstudio.model.GameDataElement; import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; +import com.gpl.rpg.atcontentstudio.ui.CollapsiblePanel; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener; import com.gpl.rpg.atcontentstudio.ui.IntegerBasedCheckBox; @@ -43,15 +45,20 @@ public class QuestEditor extends JSONElementEditor { private static final String form_view_id = "Form"; private static final String json_view_id = "JSON"; + private QuestStage selectedStage = null; + private JTextField idField; private JTextField nameField; private IntegerBasedCheckBox visibleBox; - private QuestStageTableModel stagesModel; - private JTable stagesTable; - private JButton createStage; - private JButton deleteStage; - private JButton moveUp; - private JButton moveDown; + private StagesListModel stagesListModel; + private JList stagesList; + +// private JPanel stagesParamPane; + private JSpinner progressField; + private JTextArea logTextField; + private JSpinner xpRewardField; + private IntegerBasedCheckBox finishQuestBox; + public QuestEditor(Quest quest) { @@ -72,242 +79,214 @@ public class QuestEditor extends JSONElementEditor { nameField = addTranslatableTextField(pane, "Quest Name: ", quest.name, quest.writable, listener); visibleBox = addIntegerBasedCheckBox(pane, "Visible in quest log", quest.visible_in_log, quest.writable, listener); - JPanel stagesPane = new JPanel(); - stagesPane.setLayout(new JideBoxLayout(stagesPane, JideBoxLayout.PAGE_AXIS, 6)); - stagesModel = new QuestStageTableModel(quest, listener); - stagesTable = new JTable(stagesModel); - stagesTable.getColumnModel().getColumn(0).setMinWidth(100); - stagesTable.getColumnModel().getColumn(0).setMaxWidth(100); -// stagesTable.getColumnModel().getColumn(1).setPreferredWidth(40); -// stagesTable.getColumnModel().getColumn(1).setPreferredWidth(40); - stagesTable.getColumnModel().getColumn(2).setMinWidth(100); - stagesTable.getColumnModel().getColumn(2).setMaxWidth(100); - stagesTable.getColumnModel().getColumn(3).setMinWidth(130); - stagesTable.getColumnModel().getColumn(3).setMaxWidth(130); - stagesTable.setCellSelectionEnabled(true); - stagesTable.getColumnModel().getColumn(1).setCellRenderer(new MultilineCellRenderer()); - stagesPane.add(new JScrollPane(stagesTable), BorderLayout.CENTER); - if (quest.writable) { - JPanel buttonPane = new JPanel(); - buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6)); - createStage = new JButton(new ImageIcon(DefaultIcons.getCreateIcon())); - deleteStage = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); - moveUp = new JButton(new ImageIcon(DefaultIcons.getArrowUpIcon())); - moveDown = new JButton(new ImageIcon(DefaultIcons.getArrowDownIcon())); - buttonPane.add(createStage, JideBoxLayout.FIX); - buttonPane.add(deleteStage, JideBoxLayout.FIX); - buttonPane.add(moveUp, JideBoxLayout.FIX); - buttonPane.add(moveDown, JideBoxLayout.FIX); - buttonPane.add(new JPanel(), JideBoxLayout.VARY); - deleteStage.setEnabled(false); - moveUp.setEnabled(false); - moveDown.setEnabled(false); - - stagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - - @Override - public void valueChanged(ListSelectionEvent e) { - updateTableButtons(); + CollapsiblePanel stagesPane = new CollapsiblePanel("Quest stages: "); + stagesPane.setLayout(new JideBoxLayout(stagesPane, JideBoxLayout.PAGE_AXIS)); + stagesListModel = new StagesListModel(quest); + stagesList = new JList(stagesListModel); + stagesList.setCellRenderer(new StagesCellRenderer()); + stagesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + stagesPane.add(new JScrollPane(stagesList), JideBoxLayout.FIX); + final JPanel stagesEditorPane = new JPanel(); + final JButton createStage = new JButton(new ImageIcon(DefaultIcons.getCreateIcon())); + final JButton deleteStage = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); + final JButton moveStageUp = new JButton(new ImageIcon(DefaultIcons.getArrowUpIcon())); + final JButton moveStageDown = new JButton(new ImageIcon(DefaultIcons.getArrowDownIcon())); + deleteStage.setEnabled(false); + moveStageUp.setEnabled(false); + moveStageDown.setEnabled(false); + stagesList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + selectedStage = (QuestStage) stagesList.getSelectedValue(); + if (selectedStage != null) { + deleteStage.setEnabled(true); + moveStageUp.setEnabled(stagesList.getSelectedIndex() > 0); + moveStageDown.setEnabled(stagesList.getSelectedIndex() < (stagesListModel.getSize() - 1)); + } else { + deleteStage.setEnabled(false); + moveStageUp.setEnabled(false); + moveStageDown.setEnabled(false); } - }); - + updateStageEditorPane(stagesEditorPane, selectedStage, listener); + } + }); + if (quest.writable) { + JPanel listButtonsPane = new JPanel(); + listButtonsPane.setLayout(new JideBoxLayout(listButtonsPane, JideBoxLayout.LINE_AXIS, 6)); createStage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - stagesModel.createStage(); - listener.valueChanged(stagesTable, null); - stagesTable.revalidate(); - stagesTable.repaint(); + QuestStage stage = new QuestStage(quest); + stagesListModel.addItem(stage); + stagesList.setSelectedValue(stage, true); + listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff. } }); deleteStage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - stagesModel.deleteRow(stagesTable.getSelectedRow()); - listener.valueChanged(stagesTable, null); - stagesTable.revalidate(); - stagesTable.repaint(); - updateTableButtons(); + if (selectedStage != null) { + stagesListModel.removeItem(selectedStage); + selectedStage = null; + stagesList.clearSelection(); + listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff. + } } }); - moveUp.addActionListener(new ActionListener() { + moveStageUp.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - stagesModel.moveRow(stagesTable.getSelectedRow(), true); - listener.valueChanged(stagesTable, null); - stagesTable.setRowSelectionInterval(stagesTable.getSelectedRow() - 1, stagesTable.getSelectedRow() - 1); - updateTableButtons(); + if (selectedStage != null) { + stagesListModel.moveUp(selectedStage); + stagesList.setSelectedValue(selectedStage, true); + listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff. + } } }); - moveDown.addActionListener(new ActionListener() { + moveStageDown.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - stagesModel.moveRow(stagesTable.getSelectedRow(), false); - listener.valueChanged(stagesTable, null); - stagesTable.setRowSelectionInterval(stagesTable.getSelectedRow() + 1, stagesTable.getSelectedRow() + 1); - updateTableButtons(); + if (selectedStage != null) { + stagesListModel.moveDown(selectedStage); + stagesList.setSelectedValue(selectedStage, true); + listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff. + } } }); - stagesPane.add(buttonPane, JideBoxLayout.FIX); + listButtonsPane.add(createStage, JideBoxLayout.FIX); + listButtonsPane.add(deleteStage, JideBoxLayout.FIX); + listButtonsPane.add(moveStageUp, JideBoxLayout.FIX); + listButtonsPane.add(moveStageDown, JideBoxLayout.FIX); + listButtonsPane.add(new JPanel(), JideBoxLayout.VARY); + stagesPane.add(listButtonsPane, JideBoxLayout.FIX); } + if (quest.stages == null || quest.stages.isEmpty()) { + stagesPane.collapse(); + } + stagesEditorPane.setLayout(new JideBoxLayout(stagesEditorPane, JideBoxLayout.PAGE_AXIS)); + stagesPane.add(stagesEditorPane, JideBoxLayout.FIX); pane.add(stagesPane, JideBoxLayout.FIX); } - public void updateTableButtons() { + public void updateStageEditorPane(JPanel pane, QuestStage selectedStage, FieldUpdateListener listener) { + pane.removeAll(); + if (selectedStage != null) { + boolean writable = ((Quest)target).writable; + progressField = addIntegerField(pane, "Progress ID: ", selectedStage.progress, false, writable, listener); + logTextField = addTranslatableTextArea(pane, "Log text: ", selectedStage.log_text, writable, listener); + xpRewardField = addIntegerField(pane, "XP Reward: ", selectedStage.exp_reward, false, writable, listener); + finishQuestBox = addIntegerBasedCheckBox(pane, "Finishes quest", selectedStage.finishes_quest, writable, listener); + addBacklinksList(pane, selectedStage, "Elements linking to this quest stage"); - if (stagesTable.getSelectedRow() >= 0 && stagesTable.getSelectedRow() < stagesModel.getRowCount()) { - deleteStage.setEnabled(true); - if (stagesTable.getSelectedRow() == 0) { - moveUp.setEnabled(false); - } else { - moveUp.setEnabled(true); - } - if (stagesTable.getSelectedRow() >= stagesModel.getRowCount() - 1) { - moveDown.setEnabled(false); - } else { - moveDown.setEnabled(true); - } - } else { - deleteStage.setEnabled(false); - moveUp.setEnabled(false); - moveDown.setEnabled(false); } - + pane.revalidate(); + pane.repaint(); } - public class QuestStageTableModel implements TableModel { + public static class StagesListModel implements ListModel { - Quest quest; - FieldUpdateListener listener; - - public QuestStageTableModel(Quest q, FieldUpdateListener listener) { - this.quest = q; - this.listener = listener; + Quest source; + + public StagesListModel(Quest quest) { + this.source = quest; } + @Override - public int getRowCount() { - if (quest.stages == null) return 0; - return quest.stages.size(); + public int getSize() { + if (source.stages == null) return 0; + return source.stages.size(); } @Override - public int getColumnCount() { - return 4; + public QuestStage getElementAt(int index) { + if (source.stages == null) return null; + return source.stages.get(index); } - - @Override - public String getColumnName(int columnIndex) { - switch (columnIndex) { - case 0: - return "Progress ID"; - case 1: - return "Log text"; - case 2: - return "XP reward"; - case 3: - return "Finishes quest"; - default: - return "???"; + + public void addItem(QuestStage item) { + if (source.stages == null) { + source.stages = new ArrayList(); } - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case 0: - return Integer.class; - case 1: - return String.class; - case 2: - return Integer.class; - case 3: - return Boolean.class; - default: - return null; - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return quest.writable; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - switch (columnIndex) { - case 0: - return quest.stages.get(rowIndex).progress; - case 1: - return quest.stages.get(rowIndex).log_text; - case 2: - return quest.stages.get(rowIndex).exp_reward; - case 3: - return quest.stages.get(rowIndex).finishes_quest != null && quest.stages.get(rowIndex).finishes_quest.equals(1); - default: - return null; - } - } - - @Override - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - switch (columnIndex) { - case 0: - quest.stages.get(rowIndex).progress = (Integer)aValue; - break; - case 1: - quest.stages.get(rowIndex).log_text = (String)aValue; - break; - case 2: - quest.stages.get(rowIndex).exp_reward = (Integer)aValue; - break; - case 3: - quest.stages.get(rowIndex).finishes_quest = ((Boolean)aValue) ? one : null; - break; - } - listener.valueChanged(stagesTable, aValue); - } - - public void createStage() { - if (quest.stages == null) quest.stages = new ArrayList(); - quest.stages.add(new Quest.QuestStage()); - for (TableModelListener l: listeners) { - l.tableChanged(new TableModelEvent(this, quest.stages.size() - 1)); + source.stages.add(item); + int index = source.stages.indexOf(item); + for (ListDataListener l : listeners) { + l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index)); } } - public void moveRow(int rowNumber, boolean moveUp) { - Quest.QuestStage stage = quest.stages.get(rowNumber); - quest.stages.remove(stage); - quest.stages.add(rowNumber + (moveUp ? -1 : 1), stage); - for (TableModelListener l : listeners) { - l.tableChanged(new TableModelEvent(this, rowNumber + (moveUp ? -1 : 0), rowNumber + (moveUp ? 0 : 1))); + public void removeItem(QuestStage item) { + int index = source.stages.indexOf(item); + source.stages.remove(item); + if (source.stages.isEmpty()) { + source.stages = null; + } + for (ListDataListener l : listeners) { + l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index)); + } + } + + public void itemChanged(QuestStage item) { + int index = source.stages.indexOf(item); + for (ListDataListener l : listeners) { + l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index)); } } - public void deleteRow(int rowNumber) { - quest.stages.remove(rowNumber); - for (TableModelListener l: listeners) { - l.tableChanged(new TableModelEvent(this, rowNumber, quest.stages.size())); + public void moveUp(QuestStage item) { + int index = source.stages.indexOf(item); + QuestStage exchanged = source.stages.get(index - 1); + source.stages.set(index, exchanged); + source.stages.set(index - 1, item); + for (ListDataListener l : listeners) { + l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index - 1, index)); } - if (quest.stages.isEmpty()) quest.stages = null; } - - public List listeners = new CopyOnWriteArrayList(); - + + public void moveDown(QuestStage item) { + int index = source.stages.indexOf(item); + QuestStage exchanged = source.stages.get(index + 1); + source.stages.set(index, exchanged); + source.stages.set(index + 1, item); + for (ListDataListener l : listeners) { + l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index + 1)); + } + } + + + List listeners = new CopyOnWriteArrayList(); + @Override - public void addTableModelListener(TableModelListener l) { + public void addListDataListener(ListDataListener l) { listeners.add(l); } @Override - public void removeTableModelListener(TableModelListener l) { + public void removeListDataListener(ListDataListener l) { listeners.remove(l); } - } + + public static class StagesCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 7987880146189575234L; + + @Override + public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel) { + JLabel label = ((JLabel)c); + label.setText(((QuestStage)value).getDesc()); + label.setIcon(new ImageIcon(((QuestStage)value).getIcon())); + } + return c; + } + } + + public class QuestFieldUpdater implements FieldUpdateListener { @Override @@ -337,6 +316,18 @@ public class QuestEditor extends JSONElementEditor { ATContentStudio.frame.editorChanged(QuestEditor.this); } else if (source == visibleBox) { quest.visible_in_log = (Integer) value; + } else if (source == progressField) { + selectedStage.progress = (Integer) value; + stagesListModel.itemChanged(selectedStage); + } else if (source == logTextField) { + selectedStage.log_text = (String) value; + stagesListModel.itemChanged(selectedStage); + } else if (source == xpRewardField) { + selectedStage.exp_reward = (Integer) value; + stagesListModel.itemChanged(selectedStage); + } else if (source == finishQuestBox) { + selectedStage.finishes_quest = (Integer) value; + stagesListModel.itemChanged(selectedStage); } @@ -351,47 +342,6 @@ public class QuestEditor extends JSONElementEditor { } - - public class MultilineCellRenderer extends JTextArea implements TableCellRenderer { - private static final long serialVersionUID = 6539816623608859506L; - - public MultilineCellRenderer() { - setLineWrap(true); - setWrapStyleWord(true); - //setOpaque(true); - } - - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, boolean isSelected, boolean hasFocus, - int row, int column) { - if (isSelected) { - setForeground(stagesTable.getSelectionForeground()); - setBackground(stagesTable.getSelectionBackground()); - } else { - setForeground(stagesTable.getForeground()); - setBackground(stagesTable.getBackground()); - } - setFont(stagesTable.getFont()); - if (hasFocus) { - setBorder(UIManager.getBorder("Table.focusCellHighlightBorder")); - if (stagesTable.isCellEditable(row, column)) { - setForeground(UIManager.getColor("Table.focusCellForeground")); - setBackground(UIManager.getColor("Table.focusCellBackground")); - } - } else { - setBorder(BorderFactory.createLineBorder(getBackground(), 1)); - } - setText((value == null ? "" : value.toString())); - - int fh = getFontMetrics(getFont()).getHeight(); -// int tl = getText().length(); - setSize(stagesTable.getWidth(), fh); - stagesTable.setRowHeight(row, getPreferredSize().height); - - return this; - } - } } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 03374df..52fbe53 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -15,6 +15,7 @@ import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JToolTip; +import javax.swing.SwingConstants; import javax.swing.ToolTipManager; import prefuse.Display; @@ -68,6 +69,7 @@ public class DialogueGraphView extends Display { public static final String ICON = "icon"; public static final String TARGET = "target"; public static final String REPLY = "reply"; + public static final String HIDDEN_REPLY = "hidden_reply"; public static final String HAS_REQS = "has_reqs"; private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema(); @@ -174,6 +176,7 @@ public class DialogueGraphView extends Display { graph.addColumn(ICON, Image.class, DefaultIcons.getNullifyIcon()); graph.addColumn(TARGET, GameDataElement.class, null); graph.addColumn(REPLY, Dialogue.Reply.class, null); + graph.addColumn(HIDDEN_REPLY, Dialogue.Reply.class, null); graph.addColumn(HAS_REQS, boolean.class, false); addDialogue(dialogue, npcIcon); } @@ -224,6 +227,8 @@ public class DialogueGraphView extends Display { } else if (r.next_phrase != null) { //Go directly to next phrase rNode = addDialogue(r.next_phrase, npcIcon); + //Add a pointer to the hidden reply, in order to fetch requirements later. + rNode.set(HIDDEN_REPLY, r); } else if (Dialogue.Reply.KEY_PHRASE_ID.contains(r.next_phrase_id)) { //Go directly to key phrase rNode = addKeyPhraseNode(d, r.next_phrase_id); @@ -499,27 +504,32 @@ public class DialogueGraphView extends Display { label = new JLabel(new ImageIcon(DefaultIcons.getDialogueIcon())); label.setText(d.id); content.add(label, JideBoxLayout.FIX); - if (tooltippedItem.get(REPLY) == null) { - if (d.rewards != null && !d.rewards.isEmpty()) { - for (Dialogue.Reward r : d.rewards) { - label = new JLabel(); - DialogueEditor.decorateRewardJLabel(label, r); + Object replObj = tooltippedItem.get(REPLY); + if (replObj == null) { + replObj = tooltippedItem.get(HIDDEN_REPLY); + } + if (replObj != null && replObj instanceof Dialogue.Reply) { + Dialogue.Reply r = (Dialogue.Reply) replObj; + if (r.requirements != null && !r.requirements.isEmpty()) { + JLabel reqTitle = new JLabel("--Requirements--", SwingConstants.CENTER); + content.add(reqTitle, JideBoxLayout.FIX); + for (Requirement req : r.requirements) { + label = new JLabel("", SwingConstants.CENTER); + DialogueEditor.decorateRequirementJLabel(label, req); content.add(label, JideBoxLayout.FIX); } } - } else { - Object replObj = tooltippedItem.get(REPLY); - if (replObj instanceof Dialogue.Reply) { - Dialogue.Reply r = (Dialogue.Reply) replObj; - if (r.requirements != null && !r.requirements.isEmpty()) { - for (Requirement req : r.requirements) { - label = new JLabel(); - DialogueEditor.decorateRequirementJLabel(label, req); - content.add(label, JideBoxLayout.FIX); - } - } - } } + if (d.rewards != null && !d.rewards.isEmpty()) { + JLabel rewTitle = new JLabel("--Rewards--", SwingConstants.CENTER); + rewTitle.setAlignmentY(CENTER_ALIGNMENT); + content.add(rewTitle, JideBoxLayout.FIX); + for (Dialogue.Reward r : d.rewards) { + label = new JLabel("", SwingConstants.CENTER); + DialogueEditor.decorateRewardJLabel(label, r); + content.add(label, JideBoxLayout.FIX); + } + } } } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java index 03dd81b..fb6040b 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java @@ -81,6 +81,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.Item; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement; import com.gpl.rpg.atcontentstudio.model.maps.ContainerArea; import com.gpl.rpg.atcontentstudio.model.maps.KeyArea; @@ -172,7 +173,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe @SuppressWarnings("rawtypes") private JComboBox requirementObj; private JTextField requirementObjId; - private JSpinner requirementValue; + private JComponent requirementValue; private BooleanBasedCheckBox requirementNegated; @SuppressWarnings("rawtypes") @@ -642,7 +643,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe case questProgress: requirementObj = addQuestBox(pane, project, "Quest: ", (Quest) requirement.required_obj, writable, listener); requirementObjId = null; - requirementValue = addIntegerField(pane, "Quest stage: ", requirement.required_value, false, writable, listener); + requirementValue = addQuestStageBox(pane, project, "Quest stage: ", requirement.required_value, writable, listener, (Quest) requirement.required_obj, requirementObj); break; case skillLevel: requirementObj = null; @@ -1949,11 +1950,37 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe } else if (source == requirementValue) { if (selectedMapObject instanceof KeyArea) { KeyArea area = (KeyArea) selectedMapObject; + Quest quest = null; + QuestStage stage = null; + if (requirementValue instanceof JComboBox) { + quest = ((Quest)area.requirement.required_obj); + if (quest != null && area.requirement.required_value != null) { + stage = quest.getStage(area.requirement.required_value); + if (stage != null) stage.removeBacklink(map); + } + } area.requirement.required_value = (Integer) value; + if (quest != null) { + stage = quest.getStage(area.requirement.required_value); + if (stage != null) stage.addBacklink(map); + } if (area.oldSchoolRequirement) area.updateNameFromRequirementChange(); } else if (selectedMapObject instanceof ReplaceArea) { ReplaceArea area = (ReplaceArea) selectedMapObject; + Quest quest = null; + QuestStage stage = null; + if (requirementValue instanceof JComboBox) { + quest = ((Quest)area.requirement.required_obj); + if (quest != null && area.requirement.required_value != null) { + stage = quest.getStage(area.requirement.required_value); + if (stage != null) stage.removeBacklink(map); + } + } area.requirement.required_value = (Integer) value; + if (quest != null) { + stage = quest.getStage(area.requirement.required_value); + if (stage != null) stage.addBacklink(map); + } if (area.oldSchoolRequirement) area.updateNameFromRequirementChange(); } } else if (source == requirementNegated) {