Compare commits

..

150 Commits

Author SHA1 Message Date
OMGeeky
5d5ca15669 sample 2024-01-10 19:16:12 +01:00
OMGeeky
4571bea429 fix missing " 2024-01-09 00:18:36 +01:00
OMGeeky
ecc9a35c69 Allow it to be ran on windows
(via Git-Bash)
2024-01-01 10:47:50 -08:00
OMGeeky
c4d71df4b1 Create a packaging script
This should create the zip file to distribute it
2023-12-31 14:06:31 +01:00
Nut.andor
a13dac467a Merge branch 'v0.6.20' 2023-12-26 00:43:43 +01:00
Nut.andor
e305dfd7bf new cats sprite 2023-12-26 00:35:59 +01:00
Nut.andor
80984a43af new Sprites (engine PR 59) 2023-10-03 21:20:32 +02:00
Nut.andor
2bc8b65264 version nbr 6.20
new requirements: date, dateEquals, time, timeEquals
new rewards: mapchange
2023-10-03 21:20:32 +02:00
Nut.andor
b2584a24cc export default 2023-09-24 00:25:29 +02:00
Nut.andor
1626a8340f Merge branch 'v0.6.19' 2023-09-10 19:32:25 +02:00
Nut.andor
5fe2dfe148 Merge branch 'pulls/1195352/4' into v0.6.19
Remove empty sprites from selection panel
2023-09-10 19:28:14 +02:00
Nut.andor
abc1e7c912 Ignore empty sprites in SpriteChooser 2023-09-10 19:23:30 +02:00
Nut.andor
317d6d4216 Let console open on start 2023-09-10 19:22:18 +02:00
Nut.andor
3628386019 Pull Request #4: Ignore empty sprites in SpriteChooser 2023-09-10 17:25:03 +02:00
OMGeeky
ada352a02c implement ignoring fully transparent sprites 2023-09-10 17:15:28 +02:00
OMGeeky
fc0d97aa2f reformat file & optimize usings 2023-09-10 16:11:02 +02:00
Nut.andor
7451f582ce bugfix sprite 2023-09-09 22:51:21 +02:00
Nut.andor
7b80bf5768 new png 2023-09-01 00:08:33 +02:00
Nut
ddd98c5a8f respawnspeed (originally spawnchance) renamed & added to UI
respawnspeed (originally spawnchance) renamed & added to UI
2023-08-31 23:55:14 +02:00
OMGeeky
0ef703d82e Merge remote-tracking branch 'omgeeky/spawnchance' into spawnchance 2023-08-31 23:50:15 +02:00
OMGeeky
2339a9307c respawnspeed (originally spawnchance) renamed & added to UI 2023-08-31 23:49:03 +02:00
Nut.andor
7dcdb90750 new version 2023-08-31 23:28:32 +02:00
OMGeeky
b638c31ebe update latest 2023-08-30 15:01:04 +02:00
OMGeeky
862f4b7366 respawnspeed (originally spawnchance) renamed & added to UI 2023-08-30 14:40:50 +02:00
Nut.andor
693de98212 Revert "v0.6.19"
This reverts commit 3f4bf58375.
2023-02-04 20:41:21 +01:00
Nut.andor
3f4bf58375 v0.6.19
png names
2023-02-04 03:09:18 +01:00
Nut.andor
7ae4d9d3f6 v0.6.18:
- https:
2022-09-03 23:16:48 +02:00
Nut.andor
0f20f0cd6d Sprites sorted
Missing sprites added (actorconditions, items, monster, effect)
monsters_warrior1 too much

monsters_arulir   makes ATCS crash??

and I omitted fatboy73 this time, because the png has so many holes that would be in ATCS at the beginning of NPCs
2022-02-05 03:53:59 +01:00
Nut.andor
481956cfa5 I probably didn't understand the concept of the nsi compiler, so instead of using relative or variable paths I only got it with a fix path 2022-01-30 00:24:39 +01:00
Nut.andor
7c282aae53 Missing sprites added (actorconditions, items, monster, effect)
and sorted
2022-01-29 02:16:38 +01:00
Nut.andor
1fd3e6253e Increased version number for the upcoming release 2022-01-28 23:50:07 +01:00
Gonk
70f61f0281 Prevent crash when creating a new replace area 2022-01-25 21:33:27 +01:00
Nut
2f82fd13a6 Merge pull request #2 from atsymboldot/worldmap-label-fix
Fix disappearing worldmap labels bug
2021-12-26 14:08:16 +01:00
Nut
f7e5785970 Merge pull request #1 from atsymboldot/master
Add spore immunity skill for Fungi Panic
2021-12-26 14:07:26 +01:00
Nut
084b23f641 helpful error message added 2021-12-26 14:02:14 +01:00
Nathan Watson
ff4d8a6b6c Fix disappearing worldmap labels bug
The "worldmap.labels" map is keyed by namedarea.id (corresponding to map.area), while the "mapLocations" map is keyed by map.id. This causes worldmap labels to be marked for removal when there's a namedarea.id that does not match any map.id, which happens to be true for all namedareas except crossglen and crossroads.

This logic is unnecessary anyway, because WorldMapView.pushToModel is only invoked by WorldmapSegment.pushToModel, which only triggers when maps are added or moved, but not deleted. Deletions are instead handled by WorldmapSegment.elementChanged. As such, it should never be the case that a label is removable in a pushToModel call.
2021-01-04 01:07:57 -08:00
Nathan Watson
45aff3d25b Add spore immunity skill for Fungi Panic 2020-10-11 13:49:22 -07:00
Nut
28a1d0b09e bosses 2020-10-04 22:09:43 +02:00
Gonk
b96568049f Added spritesheets 2020-08-09 20:23:22 +02:00
Gonk
e125b0339c Added the giant basilisk spritesheet. that also prevents errors during compression 2020-06-08 20:16:17 +02:00
Gonk
65456a110b Increased version number for the upcoming release 2020-05-01 20:37:07 +02:00
Gonk
a9bd84b9f2 Merged all changes from my fork. They are needed to work on AT v0.7.10 2020-05-01 20:30:17 +02:00
Gonk
1bab8dc42f Fix for ResourcesCompactor 2020-05-01 20:17:29 +02:00
Gonk
7863b73eda fixed missing png extension 2020-04-12 21:12:19 +02:00
Gonk
32e1b87e09 Corrected linking of spritesheets in tmx
- added or altered spritesheets are now linked with relative paths so that they can be committed to an ATCS project and don't have any unwanted path infomation included
- when exporting the project all links to spritesheets are now changed to ../drawable/FILENAME.PNG
2020-04-05 20:46:03 +02:00
Gonk
4b6be99d98 Changed damage modifier default value to 100% 2020-02-25 20:24:26 +01:00
Gonk
13847bb8cd Merge branch 'weapondamagemodifier' into jar20200220 2020-02-20 21:59:02 +01:00
Gonk
2d92a97689 Named the damage modifier according to the AT sources 2020-02-20 21:57:35 +01:00
Gonk
9c21c7cd02 Merge branch 'weapondamagemodifier' into jar20200121 2020-01-21 22:24:59 +01:00
Gonk
f4fd8ad5bb Merge branch 'wearremoverequirement' into jar20200121
# Conflicts:
#	src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java
#	src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java
#	src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java
2020-01-21 22:24:42 +01:00
Gonk
63acc5bf2c Merge branch 'factionscoreequals' into jar20200121 2020-01-21 22:22:13 +01:00
Gonk
4c51353e93 Merge branch 'pofileencoding' into jar20200121 2020-01-21 22:21:58 +01:00
Gonk
7bf6bbfcd1 Merge branch 'poleweapon' into jar20200121 2020-01-21 22:21:21 +01:00
Gonk
7d40d56430 The damage modifier can now be edited, also added "on hit received" columns to the items comparator 2019-12-26 21:05:39 +01:00
Gonk
d7e83575e3 wearRemove requirement
wear and wearRemove behave similar and wear now also requires the value property
2019-11-11 21:53:25 +01:00
Gonk
811870184b factionscoreEquals 2019-10-13 17:57:41 +02:00
Gonk
7297f47b67 read and write po files using utf 8 encoding
until now the system default was used, which is especially on windows not utf 8
2019-09-04 23:33:41 +02:00
Gonk
20877f7850 Changed the order for the pole weapon proficency 2019-07-11 21:21:10 +02:00
Gonk
b3c8879be1 added pole weapon proficiency 2019-07-08 22:27:23 +02:00
Zukero
ac68006a69 v0.6.15 released.
Includes a way to view which tileset a tile is from on a map. It is
shown in the tooltip from the "Testing" tab of the map editor.
2019-05-31 10:28:16 +02:00
Zukero
92e07e76d2 Added Gonk to the contributors. 2019-05-31 09:55:17 +02:00
Gonk
5a3315da1a Added random requirement and a null pointer fix for the droplist editor
- used in conversations and replace areas
- using the droplist chance editor
2019-05-12 11:45:48 +02:00
Zukero
e12c6bcc25 Overhaul of the droplist's drop chance editor, planning to use it for
the random requirement type' chance too.
2019-04-24 00:45:57 +02:00
Zukero
44c4e1f998 Merge pull request #9 from Chriz76/maprefresh 2019-04-23 20:52:44 +02:00
Gonk
450b0de02a Adjusted external map change detection
On some systems changes by tiled were not detected and therefore the refresh button was greyed. The reason might have been that tiled recreates the files instead of changing them.
2019-04-20 21:35:59 +02:00
Zukero
57702a3a4a Lib updated. 2018-11-28 15:14:08 +01:00
Zukero
3e5f732f82 Added Minify.java license 2018-09-28 09:42:50 +02:00
Zukero
b497493853 Fixed issues in i18n tools. Added beanshell worker indicator.
Added resources compression tools too.
2018-09-21 18:51:12 +02:00
Zukero
00c05e7507 Fixed Dialogue Tree bug and spacing issues.
v0.6.14 released.
Dialogue Tree bug caused by copy-pasting code created NPEs when not
activating translator mode. Made Dialogue Tree node spacing double when
activating translator mode.
2018-09-17 20:55:18 +02:00
Zukero
1b01ecd37d Version number missing in that file.... 2018-09-15 15:05:53 +02:00
Zukero
da5b686672 v0.6.13 2018-09-15 14:39:56 +02:00
Zukero
0a3da17d47 First implementation of a bookmarks system.
Not persistent yet, so you lose them all when you close ATCS.
2018-09-13 13:34:04 +02:00
Zukero
bf42f86408 Made dialogue-tree translations loading asynchronous.
Fixed quote escaping issue in english.pot generation tool.
2018-09-13 09:39:42 +02:00
Zukero
aa543bc111 Merge pull request #6 from zizkin/master
Translations
2018-09-10 10:07:27 +02:00
Jiri Zizkin Zizka
f4041ee2c7 Add myself to contributors 2018-09-10 10:02:16 +02:00
Zukero
3e8d578474 Enhanced translation-related tools.
No UI, because there's limited interest for typical users, so it's a
beanshell-only tool for now.
2018-09-08 15:37:29 +02:00
Jiri Zizkin Zizka
67b8acd20b Code more human readable 2018-09-06 22:16:33 +02:00
Jiri Zizkin Zizka
d1612269c0 Update to translation in DialogueGraphView 2018-09-06 16:12:58 +02:00
Jiri Zizkin Zizka
f95327bd12 Show translated text from Weblate in DialogueGraphView 2018-08-29 20:45:47 +02:00
Jiri Zizkin Zizka
e0425e335d Bugfix: Add missing listener in WorkspaceSettingsEditor for more intuitive behaviour of translator mode 2018-08-29 20:33:37 +02:00
Zukero
3800bf8ff0 Added code to generate new english.pot file and some tools to ease
transition of existing translations towards the new content.
2018-08-10 23:45:50 +02:00
Zukero
84e46ffd20 v0.6.12 released 2018-07-13 19:06:12 +02:00
Zukero
9f5666ea6d Fixed bugs affecting Dialogue's replies, Key Areas and Replace areas
where requirements' negation where lost upon alteration or loading.
2018-07-13 19:03:08 +02:00
Zukero
ae5822703a Fixed harmless NPE in Dialogue editor. 2018-03-26 17:41:42 +02:00
Zukero
9b68ef6679 Added missing "Faction" field to the NPC UI. 2018-03-26 17:14:10 +02:00
Zukero
75d6f8e98f v0.6.11 released. 2018-03-04 15:43:45 +01:00
Zukero
38c206cbaf TMX Maps editor's "Replacement" tab is now called "Testing" and has more
tools.
2018-03-04 15:39:30 +01:00
Zukero
b12ed1802f Added hero sprite rendering to help debug layering issues in
"Replacements" tab of TMX Map editor.
2018-03-04 12:19:56 +01:00
Zukero
0b8bc8448a Fixed memory leaks.
Closed projects were held in memory because the Map folder watcher
threads were still alive.
2018-02-28 16:25:28 +01:00
Zukero
221a031c2b Added support for new spawn area property: ignoreAreas. 2018-02-22 16:25:38 +01:00
Zukero
f2e4767eb0 Fixed export bug multiplying the data. 2018-02-18 11:28:03 +01:00
Zukero
78ceacb0ce Warnings hunt. 2018-02-13 15:26:13 +01:00
Zukero
1604373e6c Fixed icons alignment. 2018-02-13 14:11:42 +01:00
Zukero
6e2ee13da7 Fixed issue where worldmap.xml was unduely included in the generated
loadresources.xml
2018-02-12 14:18:02 +01:00
Zukero
ea28b7475a Fixed non-critical NPE. 2018-02-12 11:40:36 +01:00
Zukero
ffe6a14cd9 v0.6.10 released. 2018-02-11 13:19:28 +01:00
Zukero
3ab233761f Merge branch 'master' of https://github.com/Zukero/ATCS.git 2018-02-10 14:45:50 +01:00
Zukero
e5bb59b876 Added support for the"alignmentSet" dialogue reward type 2018-02-10 14:43:22 +01:00
Zukero
1fb22ab73f Completed formatting of loadresources.xml files generating by project
export.
2018-02-08 17:19:25 +01:00
Zukero
6b834e0f0e Added sadly convoluted way of pretty-printing loadresources.xml
Still not perfect.
2018-02-05 23:39:07 +01:00
Zukero
9e6e1d936d Fixed a bug in loadresources.xml generation.
Enhanced custom command handling for desktop tools integration.
2018-02-05 18:15:18 +01:00
Zukero
c3144db751 Fixed bug in "Npc->Effect on every hit->Actor conditions applied to the
target". Widget state wasn't updated correctly upon using the radio
buttons.
2018-02-04 11:50:32 +01:00
Zukero
daeb394373 Fixed dialogue reward editor. giveItem reward type now allows negative
amounts.
Added Nut's spritesheets to spritesheet.properties
2018-01-16 23:37:58 +01:00
Zukero
e697f93cf5 Fixed export issue zhere the loadresources.xml file couldn't be created
because its parent folder do not exist.
2017-12-18 19:04:51 +01:00
Zukero
407d50a01e Added Wizard for export project settings. Added export to game source
folder directly. Untested...
2017-12-18 18:58:09 +01:00
Zukero
a475180bb5 Fixed unwanted link following in project deletion that led to deleting
the game source's drawable folder. First steps towards enhancements of
export package generation.
2017-12-17 22:40:46 +01:00
Zukero
259442710b Merge branch 'master' of https://github.com/Zukero/ATCS.git 2017-12-09 15:51:26 +01:00
Zukero
3c63ace6c1 v0.6.9 released. 2017-12-09 15:51:03 +01:00
Zukero
1786860a3b Buf fixes for worldmaps upon contained map deletion. 2017-10-31 15:50:04 +01:00
Zukero
cbc101b3b1 Fixed parsing issue in ActorCondition.
The full round effect's visual effect was not read from the correct
field, causing NPEs.
2017-10-24 11:38:47 +02:00
Zukero
33260137d9 Bug fix in Worldmaps when a composing map is deleted. 2017-10-22 18:21:48 +02:00
Zukero
5a1d8637f9 v0.6.8 released. 2017-10-20 13:36:47 +02:00
Zukero
97119b7101 Fixed copy-pasting bug and made wording more consistent. 2017-10-09 18:52:08 +02:00
Zukero
104029124b Added support for the "revenge strike" feature in NPCs and Items.
Untested yet, and error-prone, because it was made with a LOT of
copy-paste-replacing.
2017-10-09 18:36:41 +02:00
Zukero
2aad37549c Bug fixes and added icon overlay for immunity management. 2017-08-28 13:30:08 +02:00
Zukero
8dc05bd26a Updated UI and model to support Actor Condition Immunity.
Overall, a much better UI to tune Actor Condition-based effects on
Dialogues, Items and NPCs.
2017-08-28 01:05:19 +02:00
Zukero
de0274a5be Updated version number in main class to v0.6.7. 2017-08-25 11:13:02 +02:00
Zukero
3d2dbb9f51 v0.6.7 released! 2017-08-24 20:26:43 +02:00
Zukero
f53302cb18 Font scaling is now also scaling icons, and works in most of the UI. 2017-08-24 18:37:30 +02:00
Zukero
8d6a40eb13 Added font scaling support. It's nowhere near perfect, and some look and
feels don't support it. To set it up, add the -DFONT_SCALE=1.0 (or other
float number) in the JAVA_OPTS environment variables in the startup
scripts.
2017-08-24 18:04:56 +02:00
Zukero
0199bcfb4c Small bug fixes and UI improvements. 2017-08-23 18:17:55 +02:00
Zukero
3fe895a668 Icon for alignmentChange rewards and factionScore requirements 2017-08-22 17:36:46 +02:00
Zukero
025a63af28 Visual effect widget is now a combo box, as the data is an Enum in the
game.
2017-08-21 18:32:11 +02:00
Zukero
528ac7a7e3 Added support for the new "factionScore" requirement type. 2017-08-20 11:19:54 +02:00
Zukero
506afb95ed Simple UI improvements.
Combo box to select skill ID in skill level requirement.
Icons for most requirements types in requirements list in dialogue
editor.
More verbose description of requirement in requirement list.
2017-08-19 11:47:30 +02:00
Zukero
5d802ed0e3 v0.6.6 released. 2017-08-18 22:19:29 +02:00
Zukero
33cbd059ec More bug fixes in Requirement management for Key and Replace areas.
Much better handling of the old school form, and smooth, automatic
transitionning from old school to new school, but only when necessary!
2017-08-18 17:22:06 +02:00
Zukero
6cb0941ca6 Replace areas can now use any type of requirement.
Many bug fix in Key Areas and Replace Areas, especially for the
requirements management.
2017-08-18 16:20:25 +02:00
Zukero
cfb38c33d6 Fixed bug preventing Quests with no quest stages from loading. 2017-08-18 11:51:48 +02:00
Zukero
ec3afaaf36 v0.6.5 released! 2017-08-11 22:32:54 +02:00
Zukero
9f978591ff Fixed XML-refreshing bug in TMX Map editor, and added area name editor
for key areas.
2017-08-11 22:16:08 +02:00
Zukero
7fff58d8f9 Merge branch 'master' of https://github.com/Zukero/ATCS.git 2017-08-11 21:31:57 +02:00
Zukero
6192bd8dce Fixed issue with symlinks creatipon in windows for paths containing
spaces.
2017-08-11 21:31:34 +02:00
Zukero
be43a2a5d4 Fixed display of incorrect default values when the underlying datais
null. Fixed KeyArea initialization.
2017-08-11 18:43:44 +02:00
Zukero
99524bf043 Introducing the help panel for Dialogue Sketches' editor's shortcuts. 2017-08-09 18:04:30 +02:00
Zukero
f2144ab446 Modified marker (*) handled for Dialogue Sketches too.
Typo fixed too, now displays "Dialogue sketches" instead of "Dialogue
sketchs"
2017-08-08 18:43:15 +02:00
Zukero
ada045a13b Fixed JSON import of existing element.
When an imported item was already present in the game sources, it wasnt
associated with the correct file, leading to trouble.
2017-08-08 18:25:01 +02:00
Zukero
4c4f7e5b92 Better management of scrolling in TMX Maps editor's Replacement
simulator.
2017-07-30 17:38:50 +02:00
Zukero
ef521207de v0.6.4 released. 2017-07-28 13:15:42 +02:00
Zukero
3ef0f7e0f1 Update checker now honors the "Use internet" setting. Another setting,
"check for updates" also controls this behavior.
2017-07-28 13:11:30 +02:00
Zukero
74808cdd3a Fixed a bug improperly restoring the state of WriteModeData (Dialogue
sketches) after loading it from disk. This created a risk of data loss
upon subsequent edition of dialogue sketches.
2017-07-27 20:50:10 +02:00
Zukero
1e8d08ee3a Added online version check, to warn of availability of a new version. 2017-07-27 01:07:01 +02:00
Zukero
8d8a1e122e v0.6.3 released! 2017-07-26 23:49:16 +02:00
Zukero
fe62c05b4b Fixed many bugs in the TMX Maps management. Added the
removeQuestProgress dialogue reward type. Initiallized the GDEVisitor
class to help with finding dependencies (through the Beanshell console
only for now).
2017-07-26 15:50:50 +02:00
Zukero
f93d03dbd3 Deleting a TMX Map also removes it from created/altered worldmaps, and
marks these as modified.
2017-07-25 19:16:35 +02:00
Zukero
7eb5c7c208 Fixed NPC editor bug where inflicted actor conditions weren't managed
correctly.
Fixed Worldmap saving and deletion (mostly the * management was crap)
Fixed multi-selection deletion.
2017-07-25 17:01:31 +02:00
Zukero
e04c3ee2fd v0.6.2 released! Redesigned WorldMap editor. Many new UI features. Fixed
Trainer.
2017-05-05 15:07:50 +02:00
Zukero
38a1e90aad Redesigned Worldmap editor. Better UI & support for town labels.
Searchable map list that mirrors the on-map selection.
2017-05-04 14:27:38 +02:00
Zukero
83d459021b Simple bug fix that broke the NPC icon selection window. 2017-04-21 15:55:15 +02:00
Zukero
fb8dcb9fb4 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).
2017-04-14 15:52:32 +02:00
113 changed files with 11680 additions and 3644 deletions

View File

@@ -4,6 +4,7 @@
<classpathentry kind="src" path="res"/>
<classpathentry kind="src" path="hacked-libtiled"/>
<classpathentry kind="src" path="siphash-zackehh/src/main/java"/>
<classpathentry kind="src" path="minify"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/jide-oss.jar"/>
<classpathentry kind="lib" path="lib/json_simple-1.1.jar"/>
@@ -12,7 +13,7 @@
<classpathentry kind="lib" path="lib/rsyntaxtextarea.jar"/>
<classpathentry kind="lib" path="lib/ui.jar"/>
<classpathentry kind="lib" path="lib/bsh-2.0b4.jar"/>
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.3.jar"/>
<classpathentry kind="lib" path="lib/jsoup-1.10.2.jar" sourcepath="lib/jsoup-1.10.2-sources.jar"/>
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.5.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

4
.gitignore vendored
View File

@@ -1,3 +1,7 @@
/ATCS_v*.jar
/Project
/bin
/packaging/tmp/
packaging/common/lib
packaging/common/ATCS.jar
packaging/ATCS_*.zip

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="ATContentStudio/ATCS_v0.6.0.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/ATContentStudio/ATCS_JAR.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
<javaElement handleIdentifier="=ATContentStudio/siphash-zackehh\/src\/main\/java"/>
<javaElement handleIdentifier="=ATContentStudio/res"/>
<javaElement handleIdentifier="=ATContentStudio/src"/>
<javaElement handleIdentifier="=ATContentStudio/hacked-libtiled"/>
</selectedElements>
</jardesc>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="ATContentStudio/ATCS_v0.6.20.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/ATContentStudio/ATCS_JAR.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
<javaElement handleIdentifier="=ATContentStudio/hacked-libtiled"/>
<javaElement handleIdentifier="=ATContentStudio/siphash-zackehh\/src\/main\/java"/>
<javaElement handleIdentifier="=ATContentStudio/src"/>
<javaElement handleIdentifier="=ATContentStudio/res"/>
</selectedElements>
</jardesc>

4
build-and-run.sh Executable file
View File

@@ -0,0 +1,4 @@
export MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio
export CP="lib/*:src:res:hacked-libtiled:siphash-zackehh/src/main/java/:."
javac -cp $CP ./src/com/gpl/rpg/atcontentstudio/ATContentStudio.java
java -cp $CP $MAIN_CLASS

Binary file not shown.

View File

@@ -111,11 +111,14 @@ public class Map implements Iterable<MapLayer>
public MapLayer addLayer(MapLayer layer) {
layer.setMap(this);
layers.add(layer);
if (layer instanceof TileLayer) {
tileLayers.add((TileLayer) layer);
layers.add(layer);
} else if (layer instanceof ObjectGroup) {
layers.insertElementAt(layer, objectGroups.size());
objectGroups.add((ObjectGroup) layer);
} else {
layers.add(layer);
}
return layer;
}

View File

@@ -98,27 +98,42 @@ public class TileSet implements Iterable<Tile>
File f = new File(imgFilename);
Image image = ImageIO.read(f.getCanonicalFile());
BufferedImage image = ImageIO.read(f.getCanonicalFile());
if (image == null) {
throw new IOException("Failed to load " + tilebmpFile);
throw new IOException("Failed to load " + imgFilename);
}
Toolkit tk = Toolkit.getDefaultToolkit();
tilebmpFile = f;
tileDimensions = new Rectangle(cutter.getTileDimensions());
// Toolkit tk = Toolkit.getDefaultToolkit();
//
// if (transparentColor != null) {
// int rgb = transparentColor.getRGB();
// image = tk.createImage(
// new FilteredImageSource(image.getSource(),
// new TransparentImageFilter(rgb)));
// }
//
// BufferedImage buffered = new BufferedImage(
// image.getWidth(null),
// image.getHeight(null),
// BufferedImage.TYPE_INT_ARGB);
// buffered.getGraphics().drawImage(image, 0, 0, null);
if (transparentColor != null) {
int rgb = transparentColor.getRGB();
image = tk.createImage(
new FilteredImageSource(image.getSource(),
new TransparentImageFilter(rgb)));
}
importTileBitmap(image, cutter);
}
public void weakImportTileBitmap(String imgFilename, TileCutter cutter)
throws IOException
{
setTilesetImageFilename(imgFilename);
File f = new File(imgFilename);
BufferedImage buffered = new BufferedImage(
image.getWidth(null),
image.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
buffered.getGraphics().drawImage(image, 0, 0, null);
tilebmpFile = f;
tileDimensions = new Rectangle(cutter.getTileDimensions());
importTileBitmap(buffered, cutter);
}
public void loadFromProject(String name, TMXMap tmxMap, int tileWidth, int tileHeight) {

View File

@@ -913,7 +913,8 @@ public class TMXMapReader
private class MapEntityResolver implements EntityResolver
{
public InputSource resolveEntity(String publicId, String systemId) {
if (systemId.equals("http://mapeditor.org/dtd/1.0/map.dtd")) {
if (systemId.equals("http://mapeditor.org/dtd/1.0/map.dtd") ||
systemId.equals("https://mapeditor.org/dtd/1.0/map.dtd")) {
return new InputSource(TMXMapReader.class.getResourceAsStream(
"resources/map.dtd"));
}

View File

@@ -47,6 +47,9 @@ import java.util.Vector;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPOutputStream;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import tiled.core.AnimatedTile;
import tiled.core.Map;
import tiled.core.MapLayer;
@@ -150,7 +153,7 @@ public class TMXMapWriter
}
private void writeMap(Map map, XMLWriter w, String wp) throws IOException {
w.writeDocType("map", null, "http://mapeditor.org/dtd/1.0/map.dtd");
w.writeDocType("map", null, "https://mapeditor.org/dtd/1.0/map.dtd");
w.startElement("map");
w.writeAttribute("version", "1.0");
@@ -181,7 +184,12 @@ public class TMXMapWriter
firstgid += tileset.getMaxTileId() + 1;
}
for (MapLayer layer : map) {
for (MapLayer layer : map.getTileLayers()) {
writeMapLayer(layer, w, wp);
}
for (MapLayer layer : map.getObjectGroup()) {
if (map.getTileLayers().contains(layer)) continue;
writeMapLayer(layer, w, wp);
}
firstGidPerTileset = null;
@@ -233,7 +241,15 @@ public class TMXMapWriter
} else {
w.startElement("tileset");
w.writeAttribute("firstgid", getFirstGidForTileset(set));
w.writeAttribute("source", getRelativePath(wp, source));
if (set.sheet != null && set.sheet.parent.getDataType() == Type.source) {
String fileName = set.getName();
if (fileName.length() > 3 && !(fileName.substring(fileName.length() - 4).equalsIgnoreCase(".png"))) {
fileName += ".png";
}
w.writeAttribute("source", (TMXMapSet.DEFAULT_REL_PATH_TO_DRAWABLE + fileName).replace("\\", "/"));
} else {
w.writeAttribute("source", getRelativePath(wp, source));
}
if (set.getBaseDir() != null) {
w.writeAttribute("basedir", set.getBaseDir());
}
@@ -274,7 +290,15 @@ public class TMXMapWriter
if (tileBitmapFile != null) {
w.startElement("image");
w.writeAttribute("source", getRelativePath(wp, tileBitmapFile));
if (set.sheet != null && set.sheet.parent.getDataType() == Type.source) {
String fileName = set.getName();
if (fileName.length() > 3 && !(fileName.substring(fileName.length() - 4).equalsIgnoreCase(".png"))) {
fileName += ".png";
}
w.writeAttribute("source", (TMXMapSet.DEFAULT_REL_PATH_TO_DRAWABLE + fileName).replace("\\", "/"));
} else {
w.writeAttribute("source", getRelativePath(wp, tileBitmapFile));
}
if (set.sheetDimensions != null) {
w.writeAttribute("width", set.sheetDimensions.width);
w.writeAttribute("height", set.sheetDimensions.height);

BIN
itemScroll.xcf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,405 @@
/**
* ----------------------
* Minify.java 2015-10-04
* ----------------------
*
* Copyright (c) 2015 Charles Bihis (www.whoischarles.com)
*
* This work is an adaptation of JSMin.java published by John Reilly which is a translation from C to Java of jsmin.c
* published by Douglas Crockford. Permission is hereby granted to use this Java version under the same conditions as
* the original jsmin.c on which all of these derivatives are based.
*
*
*
* ---------------------
* JSMin.java 2006-02-13
* ---------------------
*
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
*
* This work is a translation from C to Java of jsmin.c published by Douglas Crockford. Permission is hereby granted to
* use the Java version under the same conditions as the jsmin.c on which it is based.
*
*
*
* ------------------
* jsmin.c 2003-04-21
* ------------------
*
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.whoischarles.util.json;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.nio.charset.StandardCharsets;
/**
* Minify.java is written by Charles Bihis (www.whoischarles.com) and is adapted from JSMin.java written by John Reilly
* (www.inconspicuous.org) which is itself a translation of jsmin.c written by Douglas Crockford (www.crockford.com).
*
* @see <a href="http://www.unl.edu/ucomm/templatedependents/JSMin.java">http://www.unl.edu/ucomm/templatedependents/JSMin.java</a>
* @see <a href="http://www.crockford.com/javascript/jsmin.c">http://www.crockford.com/javascript/jsmin.c</a>
*/
public class Minify {
private static final int EOF = -1;
private PushbackInputStream in;
private OutputStream out;
private int currChar;
private int nextChar;
private int line;
private int column;
public static enum Action {
OUTPUT_CURR, DELETE_CURR, DELETE_NEXT
}
public Minify() {
this.in = null;
this.out = null;
}
/**
* Minifies the input JSON string.
*
* Takes the input JSON string and deletes the characters which are insignificant to JavaScipt. Comments will be
* removed, tabs will be replaced with spaces, carriage returns will be replaced with line feeds, and most spaces
* and line feeds will be removed. The result will be returned.
*
* @param json The JSON string for which to minify
* @return A minified, yet functionally identical, version of the input JSON string
*/
public String minify(String json) {
InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
minify(in, out);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return out.toString().trim();
}
/**
* Takes an input stream to a JSON string and outputs minified JSON to the output stream.
*
* Takes the input JSON via the input stream and deletes the characters which are insignificant to JavaScript.
* Comments will be removed, tabs will be replaced with spaaces, carriage returns will be replaced with line feeds,
* and most spaces and line feeds will be removed. The result is streamed to the output stream.
*
* @param in The <code>InputStream</code> from which to get the un-minified JSON
* @param out The <code>OutputStream</code> where the resulting minified JSON will be streamed to
* @throws IOException
* @throws UnterminatedRegExpLiteralException
* @throws UnterminatedCommentException
* @throws UnterminatedStringLiteralException
*/
public void minify(InputStream in, OutputStream out) throws IOException, UnterminatedRegExpLiteralException,
UnterminatedCommentException,
UnterminatedStringLiteralException {
// Initialize
this.in = new PushbackInputStream(in);
this.out = out;
this.line = 0;
this.column = 0;
// currChar = '\n';
// action(Action.DELETE_NEXT);
currChar = get();
nextChar = peek();
// Process input
while (currChar != EOF) {
switch (currChar) {
case ' ':
if (isAlphanum(nextChar)) {
action(Action.OUTPUT_CURR);
} else {
action(Action.DELETE_CURR);
}
break;
case '\n':
switch (nextChar) {
case '{':
case '[':
case '(':
case '+':
case '-':
action(Action.OUTPUT_CURR);
break;
case ' ':
action(Action.DELETE_NEXT);
break;
default:
if (isAlphanum(nextChar)) {
action(Action.OUTPUT_CURR);
} else {
action(Action.DELETE_CURR);
}
}
break;
default:
switch (nextChar) {
case ' ':
if (isAlphanum(currChar)) {
action(Action.OUTPUT_CURR);
break;
}
action(Action.DELETE_NEXT);
break;
case '\n':
switch (currChar) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
action(Action.OUTPUT_CURR);
break;
default:
if (isAlphanum(currChar)) {
action(Action.OUTPUT_CURR);
} else {
action(Action.DELETE_NEXT);
}
}
break;
default:
action(Action.OUTPUT_CURR);
break;
}
}
}
out.flush();
}
/**
* Process the current character with an appropriate action.
*
* The action that occurs is determined by the current character. The options are:
*
* 1. Output currChar: output currChar, copy nextChar to currChar, get the next character and save it to nextChar
* 2. Delete currChar: copy nextChar to currChar, get the next character and save it to nextChar
* 3. Delete nextChar: get the next character and save it to nextChar
*
* This method essentially treats a string as a single character. Also recognizes regular expressions if they are
* preceded by '(', ',', or '='.
*
* @param action The action to perform
* @throws IOException
* @throws UnterminatedRegExpLiteralException
* @throws UnterminatedCommentException
* @throws UnterminatedStringLiteralException
*/
private void action(Action action) throws IOException, UnterminatedRegExpLiteralException, UnterminatedCommentException,
UnterminatedStringLiteralException {
// Process action
switch (action) {
case OUTPUT_CURR:
out.write(currChar);
case DELETE_CURR:
currChar = nextChar;
if (currChar == '\'' || currChar == '"') {
for ( ; ; ) {
out.write(currChar);
currChar = get();
if (currChar == nextChar) {
break;
}
if (currChar <= '\n') {
throw new UnterminatedStringLiteralException(line,
column);
}
if (currChar == '\\') {
out.write(currChar);
currChar = get();
}
}
}
case DELETE_NEXT:
nextChar = next();
if (nextChar == '/'
&& (currChar == '(' || currChar == ',' || currChar == '=' || currChar == ':')) {
out.write(currChar);
out.write(nextChar);
for ( ; ; ) {
currChar = get();
if (currChar == '/') {
break;
} else if (currChar == '\\') {
out.write(currChar);
currChar = get();
} else if (currChar <= '\n') {
throw new UnterminatedRegExpLiteralException(line,
column);
}
out.write(currChar);
}
nextChar = next();
}
}
}
/**
* Determines whether a given character is a letter, digit, underscore, dollar sign, or non-ASCII character.
*
* @param c The character to compare
* @return True if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. False otherwise.
*/
private boolean isAlphanum(int c) {
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|| c == '_' || c == '$' || c == '\\' || c > 126);
}
/**
* Returns the next character from the input stream.
*
* Will pop the next character from the input stack. If the character is a control character, translate it to a space
* or line feed.
*
* @return The next character from the input stream
* @throws IOException
*/
private int get() throws IOException {
int c = in.read();
if (c == '\n') {
line++;
column = 0;
} else {
column++;
}
if (c >= ' ' || c == '\n' || c == EOF) {
return c;
}
if (c == '\r') {
column = 0;
return '\n';
}
return ' ';
}
/**
* Returns the next character from the input stream without popping it from the stack.
*
* @return The next character from the input stream
* @throws IOException
*/
private int peek() throws IOException {
int lookaheadChar = in.read();
in.unread(lookaheadChar);
return lookaheadChar;
}
/**
* Get the next character from the input stream, excluding comments.
*
* Will read from the input stream via the <code>get()</code> method. Will exclude characters that are part of
* comments. <code>peek()</code> is used to se if a '/' is followed by a '/' or a '*' for the purpose of identifying
* comments.
*
* @return The next character from the input stream, excluding characters from comments
* @throws IOException
* @throws UnterminatedCommentException
*/
private int next() throws IOException, UnterminatedCommentException {
int c = get();
if (c == '/') {
switch (peek()) {
case '/':
for ( ; ; ) {
c = get();
if (c <= '\n') {
return c;
}
}
case '*':
get();
for ( ; ; ) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case EOF:
throw new UnterminatedCommentException(line, column);
}
}
default:
return c;
}
}
return c;
}
/**
* Exception to be thrown when an unterminated comment appears in the input.
*/
public static class UnterminatedCommentException extends Exception {
public UnterminatedCommentException(int line, int column) {
super("Unterminated comment at line " + line + " and column " + column);
}
}
/**
* Exception to be thrown when an unterminated string literal appears in the input.
*/
public static class UnterminatedStringLiteralException extends Exception {
public UnterminatedStringLiteralException(int line, int column) {
super("Unterminated string literal at line " + line + " and column " + column);
}
}
/**
* Exception to be thrown when an unterminated regular expression literal appears in the input.
*/
public static class UnterminatedRegExpLiteralException extends Exception {
public UnterminatedRegExpLiteralException(int line, int column) {
super("Unterminated regular expression at line " + line + " and column " + column);
}
}
}

1
packaging/ATCS_latest Normal file
View File

@@ -0,0 +1 @@
v0.6.19

View File

@@ -4,7 +4,7 @@ set "ATCS_DIR=%~dp0"
set "MAX_MEM=512M"
set "CP=%ATCS_DIR%lib\*"
set "JAVA=javaw.exe"
set "JAVA_OPTS="
set "JAVA_OPTS=-DFONT_SCALE=1.0 -Dswing.aatext=true"
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"

View File

@@ -3,7 +3,7 @@ ATCS_DIR=$(dirname $(readlink -f "$0" || greadlink -f "$0" || stat -f "$0"))
MAX_MEM=512M
CP=$(find ${ATCS_DIR}/lib/ -name '*.jar' | paste -sd: -)
JAVA=java
JAVA_OPTS=
JAVA_OPTS='-DFONT_SCALE=1.0 -Dswing.aatext=true'
ENV_FILE=${ATCS_DIR}/ATCS.env
MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio

2
packaging/Manifest.txt Normal file
View File

@@ -0,0 +1,2 @@
Manifest-Version: 1.0
Main-Class: com.gpl.rpg.atcontentstudio.ATContentStudio

View File

@@ -4,7 +4,7 @@ set "ATCS_DIR=%~dp0"
set "MAX_MEM=512M"
set "CP=%ATCS_DIR%lib\*"
set "JAVA=javaw.exe"
set "JAVA_OPTS="
set "JAVA_OPTS=-DFONT_SCALE=1.0 -Dswing.aatext=true"
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"

View File

@@ -1,8 +1,8 @@
!include MUI2.nsh
!define VERSION "0.6.0"
!define TRAINER_VERSION "0.1.3"
!define JAVA_BIN "javaw"
!define VERSION "0.6.20"
!define TRAINER_VERSION "0.1.5"
!define JAVA_BIN "java"
Name "Andor's Trail Content Studio v${VERSION}"
OutFile "ATCS_v${VERSION}_Setup.exe"
@@ -83,16 +83,16 @@ Section install
FileClose $9
SetOutPath "$INSTDIR\lib\"
file "jide-oss.jar"
file "ui.jar"
file "AndorsTrainer_v${TRAINER_VERSION}.jar"
file "junit-4.10.jar"
file "json_simple-1.1.jar"
file "ATCS_v${VERSION}.jar"
file "rsyntaxtextarea.jar"
file "prefuse.jar"
file "bsh-2.0b4.jar"
file "jsoup-1.10.2.jar"
file "C:\AT\ATCS_source\lib\jide-oss.jar"
file "C:\AT\ATCS_source\lib\ui.jar"
file "C:\AT\ATCS_source\lib\AndorsTrainer_v${TRAINER_VERSION}.jar"
file "C:\AT\ATCS_source\lib\junit-4.10.jar"
file "C:\AT\ATCS_source\lib\json_simple-1.1.jar"
file "C:\AT\temp\ATCS_v0.6.20\ATCS_v${VERSION}.jar"
file "C:\AT\ATCS_source\lib\rsyntaxtextarea.jar"
file "C:\AT\ATCS_source\lib\prefuse.jar"
file "C:\AT\ATCS_source\lib\bsh-2.0b4.jar"
file "C:\AT\ATCS_source\lib\jsoup-1.10.2.jar"
SetOutPath $INSTDIR
@@ -172,4 +172,4 @@ Function GetJRE
JreFound:
Pop $R1
Exch $R0
FunctionEnd
FunctionEnd

18
packaging/common/ATCS.cmd Normal file
View File

@@ -0,0 +1,18 @@
@echo off
set "ATCS_DIR=%~dp0"
set "MAX_MEM=512M"
set "JAVA=javaw.exe"
set "JAVA_OPTS=-DFONT_SCALE=1.0 -Dswing.aatext=true"
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
if exist "%ENV_FILE%" (
call "%ENV_FILE%"
) else (
echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"
echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"
echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"
echo.>>"%ENV_FILE%"
)
start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -jar "%ATCS_DIR%\ATCS.jar"

View File

@@ -0,0 +1,4 @@
#MAX_MEM=512M
#JAVA=java
#JAVA_OPTS=-DFONT_SCALE=1.0 -Dswing.aatext=true

BIN
packaging/common/ATCS.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

21
packaging/common/ATCS.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
ATCS_DIR=$(dirname $(readlink -f "$0" || greadlink -f "$0" || stat -f "$0"))
MAX_MEM=512M
JAVA=java
JAVA_OPTS='-DFONT_SCALE=1.0 -Dswing.aatext=true'
ENV_FILE=${ATCS_DIR}/ATCS.env
if [ -f ${ENV_FILE} ]; then
source ${ENV_FILE}
else
echo "#MAX_MEM=${MAX_MEM}" >${ENV_FILE}
echo "#JAVA=${JAVA}" >>${ENV_FILE}
echo "#JAVA_OPTS=${JAVA_OPTS}" >>${ENV_FILE}
echo "" >>${ENV_FILE}
fi
export ENV_FILE
$JAVA ${JAVA_OPTS} -Xmx${MAX_MEM} -jar ${ATCS_DIR}/ATCS.jar

View File

@@ -0,0 +1 @@
sh ./package.sh -windows

84
packaging/package.sh Executable file
View File

@@ -0,0 +1,84 @@
#windows or linux
if [ "$1" = "-windows" ] ; then
echo "Got '-windows' flag. Running Windows version"
LINUX=false
else
echo "No '-windows' flag. Running linux version"
LINUX=true
fi
#read the folder this script should be in (should be the packaging folder inside the ATCS source)
PACKAGING_DIR=$(dirname $(readlink -f "$0" || greadlink -f "$0" || stat -f "$0"))
ATCS_SOURCE_DIR=$(dirname "${PACKAGING_DIR}")
TEMP_DIR=${PACKAGING_DIR}/tmp
echo "Packaging dir: ${PACKAGING_DIR}"
echo "ATCS_SOURCE_DIR: ${ATCS_SOURCE_DIR}"
#ATContentStudio
JAR_LOCATION="${PACKAGING_DIR}/common/ATCS.jar"
MANIFEST_LOCATION=${PACKAGING_DIR}/Manifest.txt
echo ""
echo "Getting version"
VERSION=$(cat ${PACKAGING_DIR}/ATCS_latest)
echo "Got version ${VERSION}"
echo "Removing tmp folder"
rm -rf ${PACKAGING_DIR}/tmp/
echo "recreating tmp folder"
mkdir ${PACKAGING_DIR}/tmp/
#ATCS_SOURCE_DIR="${PACKAGING_DIR}/.."
echo ""
#copy manifest to temp folder for editing
cp ${MANIFEST_LOCATION} ${TEMP_DIR}
MANIFEST_LOCATION=${TEMP_DIR}/Manifest.txt
#copy lib files to packaged folder?
echo 'copying lib files'
mkdir -p ${PACKAGING_DIR}/common/lib/
cp ${ATCS_SOURCE_DIR}/lib/* ${PACKAGING_DIR}/common/lib/
cd $ATCS_SOURCE_DIR
#set ClassPath variable to use in the building etc.
echo 'setting class path'
#linux needs a : as seperator while windows needs ;
if [ "$LINUX" = true ] ; then
CP="lib/*:src:hacked-libtiled:siphash-zackehh/src/main/java"
else
CP="lib/*;src;hacked-libtiled;siphash-zackehh/src/main/java"
fi
echo "ClassPath: "
echo ${CP}
echo ""
#set build the classes
echo 'building java classes'
#javac -cp $CP *.java
javac -cp $CP ${ATCS_SOURCE_DIR}/src/com/gpl/rpg/atcontentstudio/*.java -d ${TEMP_DIR}
echo javac -cp $CP ${ATCS_SOURCE_DIR}/src/com/gpl/rpg/atcontentstudio/*.java -d ${TEMP_DIR}
echo ""
LIB_PATHS=$(find lib -name '*.jar' | paste -sd' ')
echo "LIB_PATHS: ${LIB_PATHS}"
# add all lib files to the class path in the temp Manifest
echo "Class-Path: . lib/* ${LIB_PATHS}" >>${MANIFEST_LOCATION}
echo ""
echo "creating jar at location: ${JAR_LOCATION}"
# create the jar file
# the command with those parameters requires this format:
# jar vmfc <Manifest file> <Jar file (target location)> <all things to add to the jar file>
# the things to add always use the whole relative path from the current dir,
# so when that is not wanted, the -C <location> thing will change to that dir
jar mfc ${MANIFEST_LOCATION} ${JAR_LOCATION} -C ${PACKAGING_DIR}/tmp/ com/gpl/rpg/atcontentstudio/ -C res . -C ${ATCS_SOURCE_DIR}/src .
echo ''
echo "Done creating jar"
if [ "$LINUX" = true ] ; then
cd ${PACKAGING_DIR}
echo "Creating archive"
tar caf "ATCS_${VERSION}.tar.gz" "common"
echo "Created archive at ${PACKAGING_DIR}/ATCS_${VERSION}.tar.gz"
else
echo "Can't create zip files on windows yet. Please pack the content of the '${PACKAGING_DIR}/common/' folder yourself"
fi

43
res/LICENSE.minify.txt Normal file
View File

@@ -0,0 +1,43 @@
----------------------
Minify.java 2015-10-04
----------------------
Copyright (c) 2015 Charles Bihis (www.whoischarles.com)
This work is an adaptation of JSMin.java published by John Reilly which is a translation from C to Java of jsmin.c
published by Douglas Crockford. Permission is hereby granted to use this Java version under the same conditions as
the original jsmin.c on which all of these derivatives are based.
---------------------
JSMin.java 2006-02-13
---------------------
Copyright (c) 2006 John Reilly (www.inconspicuous.org)
This work is a translation from C to Java of jsmin.c published by Douglas Crockford. Permission is hereby granted to
use the Java version under the same conditions as the jsmin.c on which it is based.
------------------
jsmin.c 2003-04-21
------------------
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,64 +1,92 @@
atcs.spritesheet.actorconditions_1.category=actorcondition
atcs.spritesheet.actorconditions_2.category=actorcondition
atcs.spritesheet.actorconditions_japozero.category=actorcondition
atcs.spritesheet.actorconditions_omi1.category=actorcondition
atcs.spritesheet.actorconditions_omi2.category=actorcondition
atcs.spritesheet.effect_blood3.animate=true
atcs.spritesheet.effect_blood4.animate=true
atcs.spritesheet.effect_bluetentacle.animate=true
atcs.spritesheet.effect_heal2.animate=true
atcs.spritesheet.effect_miss1.animate=true
atcs.spritesheet.effect_poison1.animate=true
atcs.spritesheet.effect_tometik1.animate=true
atcs.spritesheet.effect_tometik2.animate=true
atcs.spritesheet.items_armours.category=item
atcs.spritesheet.items_armours_2.category=item
atcs.spritesheet.items_armours_3.category=item
atcs.spritesheet.items_weapons.category=item
atcs.spritesheet.items_weapons_2.category=item
atcs.spritesheet.items_weapons_3.category=item
atcs.spritesheet.items_jewelry.category=item
atcs.spritesheet.items_rings_1.category=item
atcs.spritesheet.items_necklaces_1.category=item
atcs.spritesheet.items_consumables.category=item
atcs.spritesheet.items_japozero.category=item
atcs.spritesheet.items_books.category=item
atcs.spritesheet.items_consumables.category=item
atcs.spritesheet.items_consumables_omi1.category=item
atcs.spritesheet.items_feygard1.category=item
atcs.spritesheet.items_g03_package_omi1.category=item
atcs.spritesheet.items_japozero.category=item
atcs.spritesheet.items_jewelry.category=item
atcs.spritesheet.items_misc.category=item
atcs.spritesheet.items_misc_2.category=item
atcs.spritesheet.items_misc_3.category=item
atcs.spritesheet.items_misc_4.category=item
atcs.spritesheet.items_misc_5.category=item
atcs.spritesheet.items_misc_6.category=item
atcs.spritesheet.items_necklaces_1.category=item
atcs.spritesheet.items_newb.category=item
atcs.spritesheet.items_omgeeky.category=item
atcs.spritesheet.items_omi2.category=item
atcs.spritesheet.items_phoenix01.category=item
atcs.spritesheet.items_reterski_1.category=item
atcs.spritesheet.items_rijackson_1.category=item
atcs.spritesheet.items_rings_1.category=item
atcs.spritesheet.items_tometik1.category=item
atcs.spritesheet.items_tometik2.category=item
atcs.spritesheet.items_tometik3.category=item
atcs.spritesheet.items_weapons.category=item
atcs.spritesheet.items_weapons_2.category=item
atcs.spritesheet.items_weapons_3.category=item
atcs.spritesheet.monsters_armor1.category=monster
atcs.spritesheet.monsters_arulirs.category=monster
atcs.spritesheet.monsters_cats.category=monster
atcs.spritesheet.monsters_dogs.category=monster
atcs.spritesheet.monsters_eye1.category=monster
atcs.spritesheet.monsters_eye2.category=monster
atcs.spritesheet.monsters_eye3.category=monster
atcs.spritesheet.monsters_eye4.category=monster
atcs.spritesheet.monsters_fatboy73.category=monster
atcs.spritesheet.monsters_ghost1.category=monster
atcs.spritesheet.monsters_hydra1.category=monster
atcs.spritesheet.monsters_hydra1.sizex=64
atcs.spritesheet.monsters_hydra1.sizey=64
atcs.spritesheet.monsters_gisons.category=monster
atcs.spritesheet.monsters_guynmart.category=monster
atcs.spritesheet.monsters_insects.category=monster
atcs.spritesheet.monsters_karvis1.category=monster
atcs.spritesheet.monsters_karvis2.category=monster
atcs.spritesheet.monsters_ld1.category=monster
atcs.spritesheet.monsters_ld2.category=monster
atcs.spritesheet.monsters_liches.category=monster
atcs.spritesheet.monsters_mage.category=monster
atcs.spritesheet.monsters_mage2.category=monster
atcs.spritesheet.monsters_maksiu1.category=monster
atcs.spritesheet.monsters_man1.category=monster
atcs.spritesheet.monsters_men.category=monster
atcs.spritesheet.monsters_men2.category=monster
atcs.spritesheet.monsters_misc.category=monster
atcs.spritesheet.monsters_newb_1.category=monster
atcs.spritesheet.monsters_omi1.category=monster
atcs.spritesheet.monsters_omi1_b.category=monster
atcs.spritesheet.monsters_omi2.category=monster
atcs.spritesheet.monsters_phoenix01.category=monster
atcs.spritesheet.monsters_rats.category=monster
atcs.spritesheet.monsters_rogue1.category=monster
atcs.spritesheet.monsters_skeleton1.category=monster
atcs.spritesheet.monsters_skeleton2.category=monster
atcs.spritesheet.monsters_snakes.category=monster
atcs.spritesheet.monsters_warrior1.category=monster
atcs.spritesheet.monsters_wraiths.category=monster
atcs.spritesheet.monsters_zombie1.category=monster
atcs.spritesheet.monsters_zombie2.category=monster
atcs.spritesheet.monsters_karvis1.category=monster
atcs.spritesheet.monsters_karvis2.category=monster
atcs.spritesheet.monsters_redshrike1.category=monster
atcs.spritesheet.monsters_rltiles1.category=monster
atcs.spritesheet.monsters_rltiles2.category=monster
atcs.spritesheet.monsters_rltiles3.category=monster
atcs.spritesheet.monsters_rltiles4.category=monster
atcs.spritesheet.monsters_redshrike1.category=monster
atcs.spritesheet.monsters_ld1.category=monster
atcs.spritesheet.monsters_ld2.category=monster
atcs.spritesheet.monsters_rogue1.category=monster
atcs.spritesheet.monsters_skeleton1.category=monster
atcs.spritesheet.monsters_skeleton2.category=monster
atcs.spritesheet.monsters_snakes.category=monster
atcs.spritesheet.monsters_tometik1.category=monster
atcs.spritesheet.monsters_tometik2.category=monster
atcs.spritesheet.monsters_tometik3.category=monster
@@ -69,19 +97,36 @@ atcs.spritesheet.monsters_tometik7.category=monster
atcs.spritesheet.monsters_tometik8.category=monster
atcs.spritesheet.monsters_tometik9.category=monster
atcs.spritesheet.monsters_tometik10.category=monster
atcs.spritesheet.monsters_warrior1.category=monster
atcs.spritesheet.monsters_unknown.category=monster
atcs.spritesheet.monsters_wraiths.category=monster
atcs.spritesheet.monsters_zombie1.category=monster
atcs.spritesheet.monsters_zombie2.category=monster
atcs.spritesheet.monsters_bosses_2x2.category=monster
atcs.spritesheet.monsters_bosses_2x2.sizex=64
atcs.spritesheet.monsters_bosses_2x2.sizey=64
atcs.spritesheet.monsters_cyclops.category=monster
atcs.spritesheet.monsters_cyclops.sizex=64
atcs.spritesheet.monsters_cyclops.sizey=96
atcs.spritesheet.monsters_demon1.category=monster
atcs.spritesheet.monsters_demon1.sizex=64
atcs.spritesheet.monsters_demon1.sizey=64
atcs.spritesheet.monsters_demon2.category=monster
atcs.spritesheet.monsters_demon2.sizex=64
atcs.spritesheet.monsters_demon2.sizey=64
atcs.spritesheet.monsters_cyclops.category=monster
atcs.spritesheet.monsters_cyclops.sizex=64
atcs.spritesheet.monsters_cyclops.sizey=96
atcs.spritesheet.effect_blood3.animate=true
atcs.spritesheet.effect_blood4.animate=true
atcs.spritesheet.effect_bluetentacle.animate=true
atcs.spritesheet.effect_heal2.animate=true
atcs.spritesheet.effect_poison1.animate=true
atcs.spritesheet.effect_tometik1.animate=true
atcs.spritesheet.effect_tometik2.animate=true
atcs.spritesheet.monsters_giantbasilisk.category=monster
atcs.spritesheet.monsters_giantbasilisk.sizex=64
atcs.spritesheet.monsters_giantbasilisk.sizey=64
atcs.spritesheet.monsters_hydra1.category=monster
atcs.spritesheet.monsters_hydra1.sizex=64
atcs.spritesheet.monsters_hydra1.sizey=64
atcs.spritesheet.monsters_newb_2.category=monster
atcs.spritesheet.monsters_newb_2.sizex=64
atcs.spritesheet.monsters_newb_2.sizey=32
atcs.spritesheet.monsters_newb_3.category=monster
atcs.spritesheet.monsters_newb_3.sizex=64
atcs.spritesheet.monsters_newb_3.sizey=64
atcs.spritesheet.monsters_newb_4.category=monster
atcs.spritesheet.monsters_newb_4.sizex=32
atcs.spritesheet.monsters_newb_4.sizey=64

View File

@@ -1,6 +1,11 @@
package com.zackehh.siphash;
import static com.zackehh.siphash.SipHashConstants.*;
import static com.zackehh.siphash.SipHashConstants.DEFAULT_C;
import static com.zackehh.siphash.SipHashConstants.DEFAULT_D;
import static com.zackehh.siphash.SipHashConstants.INITIAL_V0;
import static com.zackehh.siphash.SipHashConstants.INITIAL_V1;
import static com.zackehh.siphash.SipHashConstants.INITIAL_V2;
import static com.zackehh.siphash.SipHashConstants.INITIAL_V3;
/**
* Main entry point for SipHash, providing a basic hash

View File

@@ -1,98 +1,234 @@
package com.gpl.rpg.atcontentstudio;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import prefuse.data.expression.parser.ExpressionParser;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.ui.StudioFrame;
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
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 boolean STARTED = false;
public static StudioFrame frame = null;
//Need to keep a strong reference to it, to avoid garbage collection that'll reset these loggers.
public static final List<Logger> configuredLoggers = new LinkedList<Logger>();
/**
* @param args
*/
public static void main(String[] args) {
ConfigCache.init();
try {
String laf = ConfigCache.getFavoriteLaFClassName();
if (laf == null) laf = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
//Need to keep a strong reference to it, to avoid garbage collection that'll reset this setting.
Logger l = Logger.getLogger(ExpressionParser.class.getName());
l.setLevel(Level.OFF);
configuredLoggers.add(l);
final WorkspaceSelector wsSelect = new WorkspaceSelector();
wsSelect.pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = wsSelect.getSize();
wsSelect.setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
wsSelect.setVisible(true);
wsSelect.addWindowListener(new WindowAdapter() {
@Override
public synchronized void windowClosed(WindowEvent e) {
if (wsSelect.selected != null && !STARTED) {
ATContentStudio.STARTED = true;
final File workspaceRoot = new File(wsSelect.selected);
WorkerDialog.showTaskMessage("Loading your workspace...", null, new Runnable(){
public void run() {
Workspace.setActive(workspaceRoot);
frame = new StudioFrame(APP_NAME+" "+APP_VERSION);
frame.setVisible(true);
frame.setDefaultCloseOperation(StudioFrame.DO_NOTHING_ON_CLOSE);
};
});
for (File f : ConfigCache.getKnownWorkspaces()) {
if (workspaceRoot.equals(f)) {
if (!workspaceRoot.equals(ConfigCache.getLatestWorkspace())) {
ConfigCache.setLatestWorkspace(f);
}
return;
}
}
ConfigCache.addWorkspace(workspaceRoot);
ConfigCache.setLatestWorkspace(workspaceRoot);
}
}
});
}
}
package com.gpl.rpg.atcontentstudio;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.plaf.FontUIResource;
import prefuse.data.expression.parser.ExpressionParser;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.ui.StudioFrame;
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
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.20";
public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest";
public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806";
public static final String FONT_SCALE_ENV_VAR_NAME = "FONT_SCALE";
public static boolean STARTED = false;
public static float SCALING = 1.0f;
public static StudioFrame frame = null;
// Need to keep a strong reference to it, to avoid garbage collection that'll
// reset these loggers.
public static final List<Logger> configuredLoggers = new LinkedList<Logger>();
/**
* @param args
*/
public static void main(String[] args) {
String fontScaling = System.getProperty(FONT_SCALE_ENV_VAR_NAME);
Float fontScale = null;
if (fontScaling != null) {
try {
fontScale = Float.parseFloat(fontScaling);
SCALING = fontScale;
} catch (NumberFormatException e) {
System.err.println("Failed to parse font scaling parameter. Using default.");
e.printStackTrace();
}
}
ConfigCache.init();
try {
String laf = ConfigCache.getFavoriteLaFClassName();
if (laf == null)
laf = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
scaleUIFont();
// Need to keep a strong reference to it, to avoid garbage collection that'll
// reset this setting.
Logger l = Logger.getLogger(ExpressionParser.class.getName());
l.setLevel(Level.OFF);
configuredLoggers.add(l);
final WorkspaceSelector wsSelect = new WorkspaceSelector();
wsSelect.pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = wsSelect.getSize();
wsSelect.setLocation((sdim.width - wdim.width) / 2, (sdim.height - wdim.height) / 2);
wsSelect.setVisible(true);
wsSelect.addWindowListener(new WindowAdapter() {
@Override
public synchronized void windowClosed(WindowEvent e) {
if (wsSelect.selected != null && !STARTED) {
ATContentStudio.STARTED = true;
final File workspaceRoot = new File(wsSelect.selected);
WorkerDialog.showTaskMessage("Loading your workspace...", null, new Runnable() {
public void run() {
Workspace.setActive(workspaceRoot);
if (Workspace.activeWorkspace.settings.useInternet.getCurrentValue()
&& Workspace.activeWorkspace.settings.checkUpdates.getCurrentValue()) {
new Thread() {
public void run() {
checkUpdate();
}
}.start();
}
frame = new StudioFrame(APP_NAME + " " + APP_VERSION);
frame.setVisible(true);
frame.setDefaultCloseOperation(StudioFrame.DO_NOTHING_ON_CLOSE);
};
});
for (File f : ConfigCache.getKnownWorkspaces()) {
if (workspaceRoot.equals(f)) {
if (!workspaceRoot.equals(ConfigCache.getLatestWorkspace())) {
ConfigCache.setLatestWorkspace(f);
}
return;
}
}
ConfigCache.addWorkspace(workspaceRoot);
ConfigCache.setLatestWorkspace(workspaceRoot);
}
}
});
}
private static void checkUpdate() {
BufferedReader in = null;
try {
URL url = new URL(CHECK_UPDATE_URL);
in = new BufferedReader(new InputStreamReader(url.openStream()));
String inputLine, lastLine = null;
while ((inputLine = in.readLine()) != null) {
lastLine = inputLine;
}
if (lastLine != null && !lastLine.equals(APP_VERSION)) {
// for copying style
JLabel label = new JLabel();
Font font = label.getFont();
Color color = label.getBackground();
// create some css from the label's font
StringBuffer style = new StringBuffer("font-family:" + font.getFamily() + ";");
style.append("font-weight:" + (font.isBold() ? "bold" : "normal") + ";");
style.append("font-size:" + font.getSize() + "pt;");
style.append("background-color: rgb(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue()
+ ");");
JEditorPane ep = new JEditorPane("text/html",
"<html><body style=\"" + style + "\">" + "You are not running the latest ATCS version.<br/>"
+ "You can get the latest version (" + lastLine + ") by clicking the link below.<br/>"
+ "<a href=\"" + DOWNLOAD_URL + "\">" + DOWNLOAD_URL + "</a><br/>" + "<br/>"
+ "</body></html>");
ep.setEditable(false);
ep.setBorder(null);
ep.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
try {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
Desktop.getDesktop().browse(e.getURL().toURI());
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
}
});
JOptionPane.showMessageDialog(null, ep, "Update available", JOptionPane.INFORMATION_MESSAGE);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void scaleUIFont() {
if (SCALING != 1.0f) {
System.out.println("Scaling fonts to " + SCALING);
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
Map<Object, Object> newDefaults = new HashMap<Object, Object>();
for (Enumeration<Object> e = defaults.keys(); e.hasMoreElements();) {
Object key = e.nextElement();
Object value = defaults.get(key);
if (value instanceof Font) {
Font font = (Font) value;
int newSize = (int) (font.getSize() * SCALING);
if (value instanceof FontUIResource) {
newDefaults.put(key, new FontUIResource(font.getName(), font.getStyle(), newSize));
} else {
newDefaults.put(key, new Font(font.getName(), font.getStyle(), newSize));
}
}
}
for (Object key : newDefaults.keySet()) {
defaults.put(key, newDefaults.get(key));
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -11,6 +11,8 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.swing.tree.TreeNode;
import com.gpl.rpg.atcontentstudio.model.bookmarks.BookmarkEntry;
public abstract class GameDataElement implements ProjectTreeNode, Serializable {
private static final long serialVersionUID = 2028934451226743389L;
@@ -31,6 +33,8 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable {
public boolean writable = false;
public BookmarkEntry bookmark = null;
//List of objects whose transition to "linked" state made them point to this instance.
private Map<GameDataElement, Integer> backlinks = new ConcurrentHashMap<GameDataElement, Integer>();

View File

@@ -1,34 +1,58 @@
package com.gpl.rpg.atcontentstudio.model;
import java.awt.Image;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.swing.tree.TreeNode;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.json.simple.JSONArray;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
import com.gpl.rpg.atcontentstudio.io.SettingsSave;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.bookmarks.BookmarksRoot;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
@@ -39,6 +63,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;
@@ -53,7 +78,9 @@ import com.gpl.rpg.atcontentstudio.utils.FileUtils;
public class Project implements ProjectTreeNode, Serializable {
private static final long serialVersionUID = 4807454973303366758L;
private static final String drawablePath = TMXMapSet.DEFAULT_REL_PATH_TO_DRAWABLE.replace("\\", "/");
//Every instance field that is not transient will be saved in this file.
public static final String SETTINGS_FILE = ".project";
@@ -67,6 +94,8 @@ public class Project implements ProjectTreeNode, Serializable {
public GameSource referencedContent; //Pointers to base content
public transient GameSource alteredContent; //Copied from base content (does not overwrite yet)
public transient GameSource createdContent; //Stand-alone.
public transient BookmarksRoot bookmarks;
public SavedGamesSet saves; //For simulations.
@@ -115,6 +144,7 @@ public class Project implements ProjectTreeNode, Serializable {
alteredContent = new GameSource(this, GameSource.Type.altered);
createdContent = new GameSource(this, GameSource.Type.created);
bookmarks = new BookmarksRoot(this);
saves = new SavedGamesSet(this);
@@ -123,6 +153,7 @@ public class Project implements ProjectTreeNode, Serializable {
// v.add(referencedContent);
v.add(baseContent);
v.add(saves);
v.add(bookmarks);
linkAll();
@@ -221,6 +252,8 @@ public class Project implements ProjectTreeNode, Serializable {
public void refreshTransients(Workspace w) {
this.parent = w;
projectElementListeners = new HashMap<Class<? extends GameDataElement>, List<ProjectElementListener>>();
try {
knownSpritesheetsProperties = new Properties();
knownSpritesheetsProperties.load(Project.class.getResourceAsStream("/spritesheets.properties"));
@@ -240,6 +273,7 @@ public class Project implements ProjectTreeNode, Serializable {
// referencedContent.refreshTransients(this);
alteredContent = new GameSource(this, GameSource.Type.altered);
createdContent = new GameSource(this, GameSource.Type.created);
bookmarks = new BookmarksRoot(this);
saves.refreshTransients();
@@ -249,11 +283,11 @@ public class Project implements ProjectTreeNode, Serializable {
// v.add(referencedContent);
v.add(baseContent);
v.add(saves);
v.add(bookmarks);
linkAll();
projectElementListeners = new HashMap<Class<? extends GameDataElement>, List<ProjectElementListener>>();
}
public void linkAll() {
@@ -669,7 +703,7 @@ public class Project implements ProjectTreeNode, Serializable {
public Spritesheet getSpritesheet(int index) {
if (index < createdContent.gameSprites.spritesheets.size()) {
return createdContent.gameSprites.spritesheets.get(index);
} else if (index < getQuestCount()){
} else if (index < getSpritesheetCount()){
return getSpritesheet(baseContent.gameSprites.spritesheets.get(index - createdContent.gameSprites.spritesheets.size()).id);
}
return null;
@@ -758,6 +792,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);
}
@@ -940,6 +983,10 @@ public class Project implements ProjectTreeNode, Serializable {
fireElementAdded(node, getNodeIndex(node));
}
public void bookmark(GameDataElement gde) {
bookmarks.addBookmark(gde);
}
@Override
public GameDataSet getDataSet() {
@@ -1032,85 +1079,171 @@ public class Project implements ProjectTreeNode, Serializable {
}
}
public void generateExportPackage(final File target) {
public void exportProjectAsZipPackage(final File target) {
WorkerDialog.showTaskMessage("Exporting project "+name+"...", ATContentStudio.frame, true, new Runnable() {
@Override
public void run() {
Notification.addInfo("Exporting project \""+name+"\" as "+target.getAbsolutePath());
File tmpDir = new File(baseFolder, "tmp");
FileUtils.deleteDir(tmpDir);
tmpDir.mkdir();
File tmpJsonDataDir = new File(tmpDir, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpJsonDataDir.mkdirs();
for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) {
FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName()));
}
writeAltered(alteredContent.gameData.actorConditions, baseContent.gameData.actorConditions, ActorCondition.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.dialogues, baseContent.gameData.dialogues, Dialogue.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.droplists, baseContent.gameData.droplists, Droplist.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.itemCategories, baseContent.gameData.itemCategories, ItemCategory.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.items, baseContent.gameData.items, Item.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.npcs, baseContent.gameData.npcs, NPC.class, tmpJsonDataDir);
writeAltered(alteredContent.gameData.quests, baseContent.gameData.quests, Quest.class, tmpJsonDataDir);
File tmpMapDir = new File(tmpDir, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpMapDir.mkdirs();
for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(createdMapFile, new File(tmpMapDir, createdMapFile.getName()));
}
for (File alteredMapFile : alteredContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(alteredMapFile, new File(tmpMapDir, alteredMapFile.getName()));
}
if (!createdContent.worldmap.isEmpty() || !alteredContent.worldmap.isEmpty()) {
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
doc.setXmlVersion("1.0");
Element root = doc.createElement("worldmap");
doc.appendChild(root);
for (int i = 0; i < getWorldmapSegmentCount(); i++) {
root.appendChild(getWorldmapSegment(i).toXmlElement(doc));
}
Worldmap.saveDocToFile(doc, new File(tmpMapDir, "worldmap.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File tmpDir;
try {
tmpDir = exportProjectToTmpDir();
FileUtils.writeToZip(tmpDir, target);
FileUtils.deleteDir(tmpDir);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileUtils.writeToZip(tmpDir, target);
FileUtils.deleteDir(tmpDir);
Notification.addSuccess("Project \""+name+"\" exported as "+target.getAbsolutePath());
}
});
}
@SuppressWarnings("rawtypes")
public void writeAltered(GameDataCategory<? extends JSONElement> altered, GameDataCategory<? extends JSONElement> source, Class<? extends JSONElement> gdeClass, File targetFolder) {
Set<String> alteredFileNames = new LinkedHashSet<String>();
Map<String, List<Map>> toWrite = new LinkedHashMap<String, List<Map>>();
for (JSONElement gde : altered) {
alteredFileNames.add(gde.jsonFile.getName());
public void exportProjectOverGameSource(final File target) {
WorkerDialog.showTaskMessage("Exporting project "+name+"...", ATContentStudio.frame, true, new Runnable() {
@Override
public void run() {
Notification.addInfo("Exporting project \""+name+"\" into "+target.getAbsolutePath());
File tmpDir;
try {
tmpDir = exportProjectToTmpDir();
FileUtils.copyOver(tmpDir, target);
FileUtils.deleteDir(tmpDir);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Notification.addSuccess("Project \""+name+"\" exported into "+target.getAbsolutePath());
}
});
}
public File exportProjectToTmpDir() throws IOException {
File tmpDir = new File(baseFolder, "tmp");
FileUtils.deleteDir(tmpDir);
tmpDir.mkdir();
File tmpJsonDataDir = new File(tmpDir, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpJsonDataDir.mkdirs();
// for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) {
// FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName()));
// }
Map<Class<? extends GameDataElement>, List<String>> writtenFilesPerDataType = new LinkedHashMap<Class<? extends GameDataElement>, List<String>>();
List<String> writtenFiles;
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.actorConditions, alteredContent.gameData.actorConditions, baseContent.gameData.actorConditions, ActorCondition.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ActorCondition.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.dialogues, alteredContent.gameData.dialogues, baseContent.gameData.dialogues, Dialogue.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Dialogue.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.droplists, alteredContent.gameData.droplists, baseContent.gameData.droplists, Droplist.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Droplist.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.itemCategories, alteredContent.gameData.itemCategories, baseContent.gameData.itemCategories, ItemCategory.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ItemCategory.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.items, alteredContent.gameData.items, baseContent.gameData.items, Item.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Item.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.npcs, alteredContent.gameData.npcs, baseContent.gameData.npcs, NPC.class, tmpJsonDataDir);
writtenFilesPerDataType.put(NPC.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.quests, alteredContent.gameData.quests, baseContent.gameData.quests, Quest.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Quest.class, writtenFiles);
File tmpMapDir = new File(tmpDir, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpMapDir.mkdirs();
writtenFiles = new LinkedList<String>();
for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) {
if (createdMapFile.getName().equalsIgnoreCase("worldmap.xml")) continue;
copyTmxConverted(createdMapFile.toPath(), Paths.get(tmpMapDir.getAbsolutePath(), createdMapFile.getName()));
writtenFiles.add(createdMapFile.getName());
}
for (String fName : alteredFileNames) {
for (File alteredMapFile : alteredContent.gameMaps.mapFolder.listFiles()) {
if (alteredMapFile.getName().equalsIgnoreCase("worldmap.xml")) continue;
copyTmxConverted(alteredMapFile.toPath(), Paths.get(tmpMapDir.getAbsolutePath(), alteredMapFile.getName()));
writtenFiles.add(alteredMapFile.getName());
}
writtenFilesPerDataType.put(TMXMap.class, writtenFiles);
if (sourceSetToUse == ResourceSet.gameData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_GAME_RESOURCE, baseContent.baseFolder, tmpDir);
} else if (sourceSetToUse == ResourceSet.debugData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_DEBUG_RESOURCE, baseContent.baseFolder, tmpDir);
}
if (!createdContent.worldmap.isEmpty() || !alteredContent.worldmap.isEmpty()) {
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
doc.setXmlVersion("1.0");
Element root = doc.createElement("worldmap");
doc.appendChild(root);
for (int i = 0; i < getWorldmapSegmentCount(); i++) {
root.appendChild(getWorldmapSegment(i).toXmlElement(doc));
}
Worldmap.saveDocToFile(doc, new File(tmpMapDir, "worldmap.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return tmpDir;
}
private void copyTmxConverted(Path from, Path to) throws IOException {
String xml = new String(Files.readAllBytes(from), StandardCharsets.UTF_8);
xml = xml.replace("../../altered/spritesheets/", drawablePath);
xml = xml.replace("../../created/spritesheets/", drawablePath);
xml = xml.replace("../spritesheets/", drawablePath);
xml = xml.replace("../spritesheets/", drawablePath);
Files.write(to, xml.getBytes(StandardCharsets.UTF_8));
}
@SuppressWarnings("rawtypes")
public List<String> writeDataDeltaForDataType(GameDataCategory<? extends JSONElement> created, GameDataCategory<? extends JSONElement> altered, GameDataCategory<? extends JSONElement> source, Class<? extends JSONElement> gdeClass, File targetFolder) {
List<String> filenamesToWrite = new LinkedList<String>();
Map<String, List<Map>> dataToWritePerFilename = new LinkedHashMap<String, List<Map>>();
for (JSONElement gde : altered) {
if (!filenamesToWrite.contains(gde.jsonFile.getName())) {
filenamesToWrite.add(gde.jsonFile.getName());
}
}
for (JSONElement gde : created) {
if (!filenamesToWrite.contains(gde.jsonFile.getName())) {
filenamesToWrite.add(gde.jsonFile.getName());
}
}
for (String fName : filenamesToWrite) {
for (JSONElement gde : source) {
if (gde.jsonFile.getName().equals(fName)) {
if (toWrite.get(fName) == null) {
toWrite.put(fName, new ArrayList<Map>());
if (dataToWritePerFilename.get(fName) == null) {
dataToWritePerFilename.put(fName, new ArrayList<Map>());
}
toWrite.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson());
//Automatically fetches altered element over source element.
dataToWritePerFilename.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson());
}
}
for (JSONElement gde : created) {
if (gde.jsonFile.getName().equals(fName)) {
if (dataToWritePerFilename.get(fName) == null) {
dataToWritePerFilename.put(fName, new ArrayList<Map>());
}
//Add the created elements.
dataToWritePerFilename.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson());
}
}
}
for (String fName : toWrite.keySet()) {
for (String fName : dataToWritePerFilename.keySet()) {
File jsonFile = new File(targetFolder, fName);
StringWriter writer = new JsonPrettyWriter();
try {
JSONArray.writeJSONString(toWrite.get(fName), writer);
JSONArray.writeJSONString(dataToWritePerFilename.get(fName), writer);
} catch (IOException e) {
//Impossible with a StringWriter
}
@@ -1125,8 +1258,138 @@ public class Project implements ProjectTreeNode, Serializable {
e.printStackTrace();
}
}
return filenamesToWrite;
}
private void writeResourceListXml(Map<Class<? extends GameDataElement>, List<String>> writtenFilesPerDataType, String xmlFileRelPath, File baseFolder, File tmpDir) {
File xmlFile = new File(baseFolder, xmlFileRelPath);
File outputFile = new File(tmpDir, xmlFileRelPath);
Map<String, Class<? extends GameDataElement>> classNamesByArrayNames = new HashMap<String, Class<? extends GameDataElement>>();
classNamesByArrayNames.put("loadresource_itemcategories", ItemCategory.class);
classNamesByArrayNames.put("loadresource_actorconditions", ActorCondition.class);
classNamesByArrayNames.put("loadresource_items", Item.class);
classNamesByArrayNames.put("loadresource_droplists", Droplist.class);
classNamesByArrayNames.put("loadresource_quests", Quest.class);
classNamesByArrayNames.put("loadresource_conversationlists", Dialogue.class);
classNamesByArrayNames.put("loadresource_monsters", NPC.class);
classNamesByArrayNames.put("loadresource_maps", TMXMap.class);
String jsonResPrefix = "@raw/";
String tmxResPrefix = "@xml/";
String jsonFileSuffix = ".json";
String tmxFileSuffix = ".tmx";
if (!xmlFile.exists()) return;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc;
try {
factory.setIgnoringElementContentWhitespace(true);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource insrc = new InputSource(new FileInputStream(xmlFile));
insrc.setEncoding("UTF-8");
doc = builder.parse(insrc);
Element arrayNode;
String name, resPrefix, fileSuffix, resName, resToFile, fileToRes;
Class<? extends GameDataElement> clazz;
List<String> writtenFiles;
Element root = (Element) doc.getElementsByTagName("resources").item(0);
if (root != null) {
NodeList arraysList = root.getElementsByTagName("array");
if (arraysList != null) {
for (int i = 0; i < arraysList.getLength(); i++) {
arrayNode = (Element) arraysList.item(i);
name = arrayNode.getAttribute("name");
clazz = classNamesByArrayNames.get(name);
if (clazz == null) continue;
writtenFiles = writtenFilesPerDataType.get(clazz);
if (writtenFiles == null) continue;
if (clazz == TMXMap.class) {
resPrefix = tmxResPrefix;
fileSuffix = tmxFileSuffix;
} else {
resPrefix = jsonResPrefix;
fileSuffix = jsonFileSuffix;
}
NodeList arrayItems = arrayNode.getElementsByTagName("item");
if (arrayItems != null) {
for (int j = 0; j < arrayItems.getLength(); j++) {
resName = ((Element)arrayItems.item(j)).getTextContent();
if (resName == null) continue;
resToFile = resName.replaceFirst("\\A"+resPrefix, "")+fileSuffix;
writtenFiles.remove(resToFile);
}
}
if (!writtenFiles.isEmpty()) {
Comment com = doc.createComment("Added by ATCS "+ATContentStudio.APP_VERSION+" for project "+getProject().name);
arrayNode.appendChild(com);
Collections.sort(writtenFiles);
for (String missingRes : writtenFiles) {
Element item = doc.createElement("item");
fileToRes = resPrefix+missingRes.replaceFirst(fileSuffix+"\\z", "");
item.setTextContent(fileToRes);
arrayNode.appendChild(item);
}
}
}
}
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
StringWriter temp = new StringWriter();
Result output = new StreamResult(temp);
Source input = new DOMSource(doc);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.transform(input, output);
String tempString = temp.toString();
doc = builder.parse(new ByteArrayInputStream(tempString.getBytes("UTF-8")));
input = new DOMSource(doc);
transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader(
"<?xml version=\"1.0\"?>\r\n" +
"<xsl:stylesheet version=\"1.0\"\r\n" +
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\r\n" +
" <xsl:strip-space elements=\"*\" />\r\n" +
" <xsl:output method=\"xml\" indent=\"yes\" />\r\n" +
"\r\n" +
" <xsl:template match=\"node() | @*\" name=\"identity\">\r\n" +
" <xsl:copy>\r\n" +
" <xsl:apply-templates select=\"node() | @*\" />\r\n" +
" </xsl:copy>\r\n" +
" </xsl:template>\r\n" +
"\r\n" +
" <xsl:template match=\"array\">\r\n" +
" <xsl:call-template name=\"identity\"/>\r\n" +
" <xsl:text>&#xA;&#xA;&#x20;&#x20;&#x20;&#x20;</xsl:text>\r\n" +
" </xsl:template>\r\n" +
"</xsl:stylesheet>")));
output = new StreamResult(new FileOutputStream(outputFile));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(input, output);
} catch (SAXException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
@Override
public boolean needsSaving() {

View File

@@ -4,6 +4,7 @@ import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -332,7 +333,9 @@ public class Workspace implements ProjectTreeNode, Serializable {
private static boolean delete(File f) {
boolean b = true;
if (f.isDirectory()) {
if (Files.isSymbolicLink(f.toPath())) {
b &= f.delete();
} else if (f.isDirectory()) {
for (File c : f.listFiles())
b &= delete(c);
}

View File

@@ -38,10 +38,12 @@ public class WorkspaceSettings {
public static String DEFAULT_IMG_EDITOR_COMMAND = "gimp";
public Setting<String> imageEditorCommand = new PrimitiveSetting<String>("imageEditorCommand", DEFAULT_IMG_EDITOR_COMMAND);
public static String[] LANGUAGE_LIST = new String[]{null, "de", "ru", "pl", "fr", "it", "es", "nl", "uk", "ca", "sv", "pt", "pt_BR", "zh_Hant", "zh_Hans", "ja", "cs", "tr", "ko", "hu", "sl", "bg", "id", "fi", "th", "gl", "ms" ,"pa", "az"};
public static String[] LANGUAGE_LIST = new String[]{null, "de", "ru", "pl", "fr", "it", "es", "nl", "uk", "ca", "sv", "pt", "pt_BR", "zh_Hant", "zh_Hans", "ja", "cs", "tr", "ko", "hu", "sl", "bg", "id", "fi", "th", "gl", "ms" ,"pa", "az", "nb"};
public Setting<String> translatorLanguage = new NullDefaultPrimitiveSetting<String>("translatorLanguage");
public static Boolean DEFAULT_ALLOW_INTERNET = true;
public Setting<Boolean> useInternet = new PrimitiveSetting<Boolean>("useInternet", DEFAULT_ALLOW_INTERNET);
public static Boolean DEFAULT_CHECK_UPDATE = true;
public Setting<Boolean> checkUpdates = new PrimitiveSetting<Boolean>("checkUpdates", DEFAULT_CHECK_UPDATE);
public List<Setting<? extends Object>> settings = new ArrayList<Setting<? extends Object>>();
@@ -55,6 +57,7 @@ public class WorkspaceSettings {
settings.add(imageEditorCommand);
settings.add(translatorLanguage);
settings.add(useInternet);
settings.add(checkUpdates);
file = new File(parent.baseFolder, FILENAME);
if (file.exists()) {
load(file);
@@ -155,7 +158,7 @@ public class WorkspaceSettings {
value = defaultValue;
}
public abstract void readFromJson(Map json);
public abstract void readFromJson(@SuppressWarnings("rawtypes") Map json);
@SuppressWarnings({ "rawtypes", "unchecked" })
public void saveToJson(Map json) {
@@ -185,6 +188,7 @@ public class WorkspaceSettings {
super(id, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void saveToJson(Map json) {
if (value != null) json.put(id, value);
@@ -198,6 +202,7 @@ public class WorkspaceSettings {
this.value = this.defaultValue = defaultValue;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void readFromJson(Map json) {
value = new ArrayList<X>();

View File

@@ -0,0 +1,155 @@
package com.gpl.rpg.atcontentstudio.model.bookmarks;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.tree.TreeNode;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
public class BookmarkEntry implements BookmarkNode {
public GameDataElement bookmarkedElement;
public BookmarkFolder parent;
public BookmarkEntry(BookmarkFolder parent, GameDataElement target) {
this.parent = parent;
this.bookmarkedElement = target;
target.bookmark = this;
parent.contents.add(this);
}
@Override
public Enumeration<ProjectTreeNode> children() {
return null;
}
@Override
public boolean getAllowsChildren() {
return false;
}
@Override
public TreeNode getChildAt(int childIndex) {
return null;
}
@Override
public int getChildCount() {
return 0;
}
@Override
public int getIndex(TreeNode node) {
return 0;
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public boolean isLeaf() {
return true;
}
@Override
public void childrenAdded(List<ProjectTreeNode> path) {
path.add(0,this);
parent.childrenAdded(path);
}
@Override
public void childrenChanged(List<ProjectTreeNode> path) {
path.add(0,this);
parent.childrenChanged(path);
}
@Override
public void childrenRemoved(List<ProjectTreeNode> path) {
path.add(0,this);
parent.childrenRemoved(path);
}
@Override
public void notifyCreated() {
childrenAdded(new ArrayList<ProjectTreeNode>());
}
@Override
public String getDesc() {
if (bookmarkedElement instanceof QuestStage) {
String text = ((GameDataElement)bookmarkedElement).getDesc();
if (text.length() > 60) {
text = text.substring(0, 57)+"...";
}
return ((GameDataElement)bookmarkedElement).getDataType().toString()+"/"+((Quest)((QuestStage)bookmarkedElement).parent).id+"#"+((QuestStage)bookmarkedElement).progress+":"+text;
} else {
return ((GameDataElement)bookmarkedElement).getDataType().toString()+"/"+((GameDataElement)bookmarkedElement).getDesc();
}
}
@Override
public Project getProject() {
return parent.getProject();
}
@Override
public GameDataSet getDataSet() {
return null;
}
@Override
public Image getIcon() {
return bookmarkedElement.getIcon();
}
@Override
public Image getOpenIcon() {
return null;
}
@Override
public Image getClosedIcon() {
return null;
}
@Override
public Image getLeafIcon() {
return getIcon();
}
@Override
public Type getDataType() {
return null;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public boolean needsSaving() {
return false;
}
public void delete() {
bookmarkedElement.bookmark = null;
parent.delete(this);
}
@Override
public void save() {
parent.save();
}
}

View File

@@ -0,0 +1,168 @@
package com.gpl.rpg.atcontentstudio.model.bookmarks;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import javax.swing.tree.TreeNode;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class BookmarkFolder implements BookmarkNode {
List<BookmarkNode> contents = new LinkedList<BookmarkNode>();
BookmarkNode parent;
String name;
Image closedIcon, openIcon;
public BookmarkFolder(BookmarkNode parent, String name) {
this(parent, name, DefaultIcons.getStdClosedIcon(), DefaultIcons.getStdOpenIcon());
}
public BookmarkFolder(BookmarkNode parent, String name, Image closedIcon, Image openIcon) {
this.parent = parent;
this.name = name;
this.closedIcon = closedIcon;
this.openIcon = openIcon;
}
@Override
public Enumeration<? extends ProjectTreeNode> children() {
return Collections.enumeration(contents);
}
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public TreeNode getChildAt(int childIndex) {
return contents.get(childIndex);
}
@Override
public int getChildCount() {
return contents.size();
}
@Override
public int getIndex(TreeNode node) {
return contents.indexOf(node);
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public void childrenAdded(List<ProjectTreeNode> path) {
path.add(0,this);
parent.childrenAdded(path);
}
@Override
public void childrenChanged(List<ProjectTreeNode> path) {
path.add(0,this);
parent.childrenChanged(path);
}
@Override
public void childrenRemoved(List<ProjectTreeNode> path) {
if (path.size() == 1 && this.getChildCount() == 1) {
childrenRemoved(new ArrayList<ProjectTreeNode>());
} else {
path.add(0, this);
parent.childrenRemoved(path);
}
}
@Override
public void notifyCreated() {
childrenAdded(new ArrayList<ProjectTreeNode>());
}
@Override
public String getDesc() {
return name;
}
@Override
public Project getProject() {
return parent.getProject();
}
@Override
public GameDataSet getDataSet() {
return null;
}
@Override
public Image getIcon() {
return getClosedIcon();
}
@Override
public Image getOpenIcon() {
return openIcon;
}
@Override
public Image getClosedIcon() {
return closedIcon;
}
@Override
public Image getLeafIcon() {
return getClosedIcon();
}
@Override
public Type getDataType() {
return null;
}
@Override
public boolean isEmpty() {
return contents.isEmpty();
}
@Override
public boolean needsSaving() {
return false;
}
public void delete(BookmarkEntry bookmarkEntry) {
if (contents.contains(bookmarkEntry)) {
bookmarkEntry.childrenRemoved(new ArrayList<ProjectTreeNode>());
contents.remove(bookmarkEntry);
save();
}
}
public void delete(BookmarkFolder bookmarkFolder) {
// TODO Auto-generated method stub
}
public void save() {
parent.save();
}
public void delete() {
}
}

View File

@@ -0,0 +1,10 @@
package com.gpl.rpg.atcontentstudio.model.bookmarks;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
public interface BookmarkNode extends ProjectTreeNode{
public void save();
public void delete();
}

View File

@@ -0,0 +1,210 @@
package com.gpl.rpg.atcontentstudio.model.bookmarks;
import java.awt.Image;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.tree.TreeNode;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.SavedSlotCollection;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class BookmarksRoot implements BookmarkNode {
SavedSlotCollection v = new SavedSlotCollection();
public transient Project parent = null;
BookmarkFolder ac, diag, dl, it, ic, npc, q, tmx, sp, wm;
public BookmarksRoot(Project parent) {
this.parent = parent;
v.add(ac = new BookmarkFolder(this, ActorCondition.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(diag = new BookmarkFolder(this, Dialogue.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(dl = new BookmarkFolder(this, Droplist.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(it = new BookmarkFolder(this, Item.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(ic = new BookmarkFolder(this, ItemCategory.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(npc = new BookmarkFolder(this, NPC.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(q = new BookmarkFolder(this, Quest.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon()));
v.add(tmx = new BookmarkFolder(this, "TMX Maps", DefaultIcons.getTmxClosedIcon(), DefaultIcons.getTmxOpenIcon()));
v.add(sp = new BookmarkFolder(this, "Spritesheets", DefaultIcons.getSpriteClosedIcon(), DefaultIcons.getSpriteOpenIcon()));
v.add(wm = new BookmarkFolder(this, "Worldmap", DefaultIcons.getSpriteClosedIcon(), DefaultIcons.getSpriteOpenIcon()));
}
@Override
public Enumeration<ProjectTreeNode> children() {
return v.getNonEmptyElements();
}
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public TreeNode getChildAt(int arg0) {
return v.getNonEmptyElementAt(arg0);
}
@Override
public int getChildCount() {
return v.getNonEmptySize();
}
@Override
public int getIndex(TreeNode arg0) {
return v.getNonEmptyIndexOf((ProjectTreeNode) arg0);
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public void childrenAdded(List<ProjectTreeNode> path) {
path.add(0, this);
parent.childrenAdded(path);
}
@Override
public void childrenChanged(List<ProjectTreeNode> path) {
path.add(0, this);
parent.childrenChanged(path);
}
@Override
public void childrenRemoved(List<ProjectTreeNode> path) {
if (path.size() == 1 && this.v.getNonEmptySize() == 1) {
childrenRemoved(new ArrayList<ProjectTreeNode>());
} else {
path.add(0, this);
parent.childrenRemoved(path);
}
}
@Override
public void notifyCreated() {
childrenAdded(new ArrayList<ProjectTreeNode>());
for (ProjectTreeNode node : v.getNonEmptyIterable()) {
node.notifyCreated();
}
}
@Override
public String getDesc() {
return (needsSaving() ? "*" : "")+"Bookmarks";
}
@Override
public Project getProject() {
return parent == null ? null : parent.getProject();
}
@Override
public GameDataSet getDataSet() {
return null;
}
@Override
public Image getIcon() {
return getOpenIcon();
}
@Override
public Image getOpenIcon() {
return DefaultIcons.getBookmarkOpenIcon();
}
@Override
public Image getClosedIcon() {
return DefaultIcons.getBookmarkClosedIcon();
}
@Override
public Image getLeafIcon() {
return getClosedIcon();
}
@Override
public Type getDataType() {
return null;
}
@Override
public boolean isEmpty() {
return v.isEmpty();
}
@Override
public boolean needsSaving() {
return false;
}
public void save() {
}
@Override
public void delete() {}
public void addBookmark(GameDataElement target) {
BookmarkEntry node;
BookmarkFolder folder = null;
if (target instanceof ActorCondition) {
folder = ac;
} else if (target instanceof Dialogue) {
folder = diag;
} else if (target instanceof Droplist) {
folder = dl;
} else if (target instanceof Item) {
folder = it;
} else if (target instanceof ItemCategory) {
folder = ic;
} else if (target instanceof NPC) {
folder = npc;
} else if (target instanceof Quest) {
folder = q;
} else if (target instanceof TMXMap) {
folder = tmx;
} else if (target instanceof Spritesheet) {
folder = sp;
} else if (target instanceof WorldmapSegment) {
folder = wm;
} else {
return;
}
ProjectTreeNode higherEmptyParent = folder;
while (higherEmptyParent != null) {
if (higherEmptyParent.getParent() != null && ((ProjectTreeNode)higherEmptyParent.getParent()).isEmpty()) higherEmptyParent = (ProjectTreeNode)higherEmptyParent.getParent();
else break;
}
if (higherEmptyParent == this && !this.isEmpty()) higherEmptyParent = null;
node = new BookmarkEntry(folder, target);
if (higherEmptyParent != null) higherEmptyParent.notifyCreated();
else node.notifyCreated();
}
}

View File

@@ -21,7 +21,9 @@ public class ActorCondition extends JSONElement {
private static final long serialVersionUID = -3969824899972048507L;
public static final Integer CLEAR_AC_MAGNITUDE = -99;
public static final Integer MAGNITUDE_CLEAR = -99;
public static final Integer DURATION_FOREVER = 999;;
public static final Integer DURATION_NONE = 0;
// Available from init state
//public String id; inherited.
@@ -43,9 +45,16 @@ public class ActorCondition extends JSONElement {
blood
}
public static enum VisualEffectID {
redSplash
,blueSwirl
,greenSplash
,miss
}
public static class RoundEffect implements Cloneable {
// Available from parsed state
public String visual_effect = null;
public VisualEffectID visual_effect = null;
public Integer hp_boost_min = null;
public Integer hp_boost_max = null;
public Integer ap_boost_min = null;
@@ -180,7 +189,13 @@ public class ActorCondition extends JSONElement {
this.round_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)roundEffect.get("increaseCurrentAP")).get("max")));
this.round_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)roundEffect.get("increaseCurrentAP")).get("min")));
}
this.round_effect.visual_effect = (String) roundEffect.get("visualEffectID");
String vfx = (String) roundEffect.get("visualEffectID");
this.round_effect.visual_effect = null;
if (vfx != null) {
try {
this.round_effect.visual_effect = VisualEffectID.valueOf(vfx);
} catch(IllegalArgumentException e) {}
}
}
Map fullRoundEffect = (Map) aCondJson.get("fullRoundEffect");
if (fullRoundEffect != null) {
@@ -193,7 +208,13 @@ public class ActorCondition extends JSONElement {
this.full_round_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)fullRoundEffect.get("increaseCurrentAP")).get("max")));
this.full_round_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)fullRoundEffect.get("increaseCurrentAP")).get("min")));
}
this.full_round_effect.visual_effect = (String) fullRoundEffect.get("visualEffectID");
String vfx = (String) fullRoundEffect.get("visualEffectID");
this.full_round_effect.visual_effect = null;
if (vfx != null) {
try {
this.full_round_effect.visual_effect = VisualEffectID.valueOf(vfx);
} catch(IllegalArgumentException e) {}
}
}
this.state = State.parsed;
@@ -214,6 +235,9 @@ public class ActorCondition extends JSONElement {
}
if (this.icon_id != null) {
String spritesheetId = this.icon_id.split(":")[0];
if (getProject().getSpritesheet(spritesheetId) == null) {
System.out.println(this.id);
}
getProject().getSpritesheet(spritesheetId).addBacklink(this);
}
@@ -275,7 +299,7 @@ public class ActorCondition extends JSONElement {
if (this.stacking != null && this.stacking == 1) jsonAC.put("isStacking", this.stacking);
if (this.round_effect != null) {
Map jsonRound = new LinkedHashMap();
if (this.round_effect.visual_effect != null) jsonRound.put("visualEffectID", this.round_effect.visual_effect);
if (this.round_effect.visual_effect != null) jsonRound.put("visualEffectID", this.round_effect.visual_effect.toString());
if (this.round_effect.hp_boost_min != null || this.round_effect.hp_boost_max != null) {
Map jsonHP = new LinkedHashMap();
if (this.round_effect.hp_boost_min != null) jsonHP.put("min", this.round_effect.hp_boost_min);
@@ -296,7 +320,7 @@ public class ActorCondition extends JSONElement {
}
if (this.full_round_effect != null) {
Map jsonFullRound = new LinkedHashMap();
if (this.full_round_effect.visual_effect != null) jsonFullRound.put("visualEffectID", this.full_round_effect.visual_effect);
if (this.full_round_effect.visual_effect != null) jsonFullRound.put("visualEffectID", this.full_round_effect.visual_effect.toString());
if (this.full_round_effect.hp_boost_min != null || this.full_round_effect.hp_boost_max != null) {
Map jsonHP = new LinkedHashMap();
if (this.full_round_effect.hp_boost_min != null) jsonHP.put("min", this.full_round_effect.hp_boost_min);

View File

@@ -54,10 +54,13 @@ public class Dialogue extends JSONElement {
public enum RewardType {
questProgress,
removeQuestProgress,
dropList,
skillIncrease,
actorCondition,
actorConditionImmunity,
alignmentChange,
alignmentSet,
giveItem,
createTimer,
spawnAll,
@@ -65,7 +68,8 @@ public class Dialogue extends JSONElement {
deactivateSpawnArea,
activateMapObjectGroup,
deactivateMapObjectGroup,
changeMapFilter
changeMapFilter,
mapchange
}
}
@@ -246,13 +250,16 @@ public class Dialogue extends JSONElement {
case removeSpawnArea:
case deactivateSpawnArea:
case changeMapFilter:
case mapchange:
reward.map = reward.map_name != null ? proj.getMap(reward.map_name) : null;
break;
case actorCondition:
case actorConditionImmunity:
reward.reward_obj = proj.getActorCondition(reward.reward_obj_id);
break;
case alignmentChange:
//Nothing to do (yet ?).
case alignmentSet:
//Nothing to do (yet ?).
break;
case createTimer:
//Nothing to do.
@@ -264,7 +271,14 @@ public class Dialogue extends JSONElement {
reward.reward_obj = proj.getItem(reward.reward_obj_id);
break;
case questProgress:
case removeQuestProgress:
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 +375,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 +387,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);
}
}
}
}
}

View File

@@ -36,7 +36,7 @@ public class Droplist extends JSONElement {
public static class DroppedItem {
//Available from parsed state;
public String item_id = null;
public Double chance = null;
public String chance = null;
public Integer quantity_min = null;
public Integer quantity_max = null;
@@ -114,7 +114,8 @@ public class Droplist extends JSONElement {
Map droppedItemJson = (Map)droppedItemJsonObj;
DroppedItem droppedItem = new DroppedItem();
droppedItem.item_id = (String) droppedItemJson.get("itemID");
if (droppedItemJson.get("chance") != null) droppedItem.chance = JSONElement.parseChance(droppedItemJson.get("chance").toString());
//if (droppedItemJson.get("chance") != null) droppedItem.chance = JSONElement.parseChance(droppedItemJson.get("chance").toString());
droppedItem.chance = (String) droppedItemJson.get("chance");
Map droppedItemQtyJson = (Map) droppedItemJson.get("quantity");
if (droppedItemQtyJson != null) {
droppedItem.quantity_min = JSONElement.getInteger((Number) droppedItemQtyJson.get("min"));
@@ -217,7 +218,8 @@ public class Droplist extends JSONElement {
} else if (droppedItem.item_id != null) {
droppedItemJson.put("itemID", droppedItem.item_id);
}
if (droppedItem.chance != null) droppedItemJson.put("chance", JSONElement.printJsonChance(droppedItem.chance));
//if (droppedItem.chance != null) droppedItemJson.put("chance", JSONElement.printJsonChance(droppedItem.chance));
if (droppedItem.chance != null) droppedItemJson.put("chance", droppedItem.chance);
if (droppedItem.quantity_min != null || droppedItem.quantity_max != null) {
Map quantityJson = new LinkedHashMap();
droppedItemJson.put("quantity", quantityJson);

View File

@@ -34,6 +34,7 @@ public class Item extends JSONElement {
public String category_id = null;
public String description = null;
public HitEffect hit_effect = null;
public HitReceivedEffect hit_received_effect = null;
public KillEffect kill_effect = null;
public EquipEffect equip_effect = null;
@@ -58,6 +59,14 @@ public class Item extends JSONElement {
public List<TimedConditionEffect> conditions_target = null;
}
public static class HitReceivedEffect extends HitEffect {
//Available from parsed state
public Integer hp_boost_min_target = null;
public Integer hp_boost_max_target = null;
public Integer ap_boost_min_target = null;
public Integer ap_boost_max_target = null;
}
public static class EquipEffect {
//Available from parsed state
public Integer damage_boost_min = null;
@@ -74,6 +83,7 @@ public class Item extends JSONElement {
public Integer increase_block_chance = null;
public Integer increase_damage_resistance = null;
public Double critical_multiplier = null;
public Integer damage_modifier = null;
}
public static class ConditionEffect {
@@ -193,7 +203,8 @@ public class Item extends JSONElement {
//TODO correct game data, to unify format.
// this.equip_effect.critical_multiplier = JSONElement.getDouble((Number) equipEffect.get("setCriticalMultiplier"));
if (equipEffect.get("setCriticalMultiplier") != null) this.equip_effect.critical_multiplier = JSONElement.getDouble(Double.parseDouble(equipEffect.get("setCriticalMultiplier").toString()));
this.equip_effect.damage_modifier = JSONElement.getInteger((Number) equipEffect.get("setNonWeaponDamageModifier"));
List conditionsJson = (List) equipEffect.get("addedConditions");
if (conditionsJson != null && !conditionsJson.isEmpty()) {
this.equip_effect.conditions = new ArrayList<Item.ConditionEffect>();
@@ -207,6 +218,7 @@ public class Item extends JSONElement {
}
}
Map hitEffect = (Map) itemJson.get("hitEffect");
if (hitEffect != null) {
this.hit_effect = new HitEffect();
@@ -246,6 +258,53 @@ public class Item extends JSONElement {
}
}
Map hitReceivedEffect = (Map) itemJson.get("hitReceivedEffect");
if (hitReceivedEffect != null) {
this.hit_received_effect = new HitReceivedEffect();
if (hitReceivedEffect.get("increaseCurrentHP") != null) {
this.hit_received_effect.hp_boost_min = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentHP")).get("min")));
this.hit_received_effect.hp_boost_max = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentHP")).get("max")));
}
if (hitReceivedEffect.get("increaseCurrentAP") != null) {
this.hit_received_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentAP")).get("min")));
this.hit_received_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentAP")).get("max")));
}
if (hitReceivedEffect.get("increaseAttackerCurrentHP") != null) {
this.hit_received_effect.hp_boost_min_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentHP")).get("min")));
this.hit_received_effect.hp_boost_max_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentHP")).get("max")));
}
if (hitReceivedEffect.get("increaseAttackerCurrentAP") != null) {
this.hit_received_effect.ap_boost_min_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentAP")).get("min")));
this.hit_received_effect.ap_boost_max_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentAP")).get("max")));
}
List conditionsSourceJson = (List) hitReceivedEffect.get("conditionsSource");
if (conditionsSourceJson != null && !conditionsSourceJson.isEmpty()) {
this.hit_received_effect.conditions_source = new ArrayList<Item.TimedConditionEffect>();
for (Object conditionJsonObj : conditionsSourceJson) {
Map conditionJson = (Map)conditionJsonObj;
TimedConditionEffect condition = new TimedConditionEffect();
condition.condition_id = (String) conditionJson.get("condition");
condition.magnitude = JSONElement.getInteger((Number) conditionJson.get("magnitude"));
condition.duration = JSONElement.getInteger((Number) conditionJson.get("duration"));
if (conditionJson.get("chance") != null) condition.chance = JSONElement.parseChance(conditionJson.get("chance").toString());
this.hit_received_effect.conditions_source.add(condition);
}
}
List conditionsTargetJson = (List) hitReceivedEffect.get("conditionsTarget");
if (conditionsTargetJson != null && !conditionsTargetJson.isEmpty()) {
this.hit_received_effect.conditions_target = new ArrayList<Item.TimedConditionEffect>();
for (Object conditionJsonObj : conditionsTargetJson) {
Map conditionJson = (Map)conditionJsonObj;
TimedConditionEffect condition = new TimedConditionEffect();
condition.condition_id = (String) conditionJson.get("condition");
condition.magnitude = JSONElement.getInteger((Number) conditionJson.get("magnitude"));
condition.duration = JSONElement.getInteger((Number) conditionJson.get("duration"));
if (conditionJson.get("chance") != null) condition.chance = JSONElement.parseChance(conditionJson.get("chance").toString());
this.hit_received_effect.conditions_target.add(condition);
}
}
}
Map killEffect = (Map) itemJson.get("killEffect");
if (killEffect == null) {
killEffect = (Map) itemJson.get("useEffect");
@@ -321,6 +380,18 @@ public class Item extends JSONElement {
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.hit_received_effect != null && this.hit_received_effect.conditions_source != null) {
for (TimedConditionEffect ce : this.hit_received_effect.conditions_source) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.hit_received_effect != null && this.hit_received_effect.conditions_target != null) {
for (TimedConditionEffect ce : this.hit_received_effect.conditions_target) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.kill_effect != null && this.kill_effect.conditions_source != null) {
for (TimedConditionEffect ce : this.kill_effect.conditions_source) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
@@ -358,6 +429,7 @@ public class Item extends JSONElement {
clone.has_manual_price = this.has_manual_price;
if (this.equip_effect != null) {
clone.equip_effect = new EquipEffect();
clone.equip_effect.damage_modifier = this.equip_effect.damage_modifier;
clone.equip_effect.critical_multiplier = this.equip_effect.critical_multiplier;
clone.equip_effect.damage_boost_max = this.equip_effect.damage_boost_max;
clone.equip_effect.damage_boost_min = this.equip_effect.damage_boost_min;
@@ -422,6 +494,47 @@ public class Item extends JSONElement {
}
}
}
if (this.hit_received_effect != null) {
clone.hit_received_effect = new HitReceivedEffect();
clone.hit_received_effect.ap_boost_max = this.hit_received_effect.ap_boost_max;
clone.hit_received_effect.ap_boost_min = this.hit_received_effect.ap_boost_min;
clone.hit_received_effect.hp_boost_max = this.hit_received_effect.hp_boost_max;
clone.hit_received_effect.hp_boost_min = this.hit_received_effect.hp_boost_min;
clone.hit_received_effect.ap_boost_max_target = this.hit_received_effect.ap_boost_max_target;
clone.hit_received_effect.ap_boost_min_target = this.hit_received_effect.ap_boost_min_target;
clone.hit_received_effect.hp_boost_max_target = this.hit_received_effect.hp_boost_max_target;
clone.hit_received_effect.hp_boost_min_target = this.hit_received_effect.hp_boost_min_target;
if (this.hit_received_effect.conditions_source != null) {
clone.hit_received_effect.conditions_source = new ArrayList<Item.TimedConditionEffect>();
for (TimedConditionEffect c : this.hit_received_effect.conditions_source) {
TimedConditionEffect cclone = new TimedConditionEffect();
cclone.magnitude = c.magnitude;
cclone.condition_id = c.condition_id;
cclone.condition = c.condition;
cclone.chance = c.chance;
cclone.duration = c.duration;
if (cclone.condition != null) {
cclone.condition.addBacklink(clone);
}
clone.hit_received_effect.conditions_source.add(cclone);
}
}
if (this.hit_received_effect.conditions_target != null) {
clone.hit_received_effect.conditions_target = new ArrayList<Item.TimedConditionEffect>();
for (TimedConditionEffect c : this.hit_received_effect.conditions_target) {
TimedConditionEffect cclone = new TimedConditionEffect();
cclone.magnitude = c.magnitude;
cclone.condition_id = c.condition_id;
cclone.condition = c.condition;
cclone.chance = c.chance;
cclone.duration = c.duration;
if (cclone.condition != null) {
cclone.condition.addBacklink(clone);
}
clone.hit_received_effect.conditions_target.add(cclone);
}
}
}
if (this.kill_effect != null) {
clone.kill_effect = new KillEffect();
clone.kill_effect.ap_boost_max = this.kill_effect.ap_boost_max;
@@ -533,6 +646,7 @@ public class Item extends JSONElement {
if (this.equip_effect.increase_block_chance != null) equipEffectJson.put("increaseBlockChance", this.equip_effect.increase_block_chance);
if (this.equip_effect.increase_damage_resistance != null) equipEffectJson.put("increaseDamageResistance", this.equip_effect.increase_damage_resistance);
if (this.equip_effect.critical_multiplier != null) equipEffectJson.put("setCriticalMultiplier", this.equip_effect.critical_multiplier);
if (this.equip_effect.damage_modifier != null) equipEffectJson.put("setNonWeaponDamageModifier", this.equip_effect.damage_modifier);
if (this.equip_effect.conditions != null) {
List conditionsJson = new ArrayList();
equipEffectJson.put("addedConditions", conditionsJson);
@@ -600,6 +714,74 @@ public class Item extends JSONElement {
}
}
}
if (this.hit_received_effect != null) {
Map hitReceivedEffectJson = new LinkedHashMap();
itemJson.put("hitReceivedEffect", hitReceivedEffectJson);
if (this.hit_received_effect.hp_boost_min != null || this.hit_received_effect.hp_boost_max != null) {
Map hpJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseCurrentHP", hpJson);
if (this.hit_received_effect.hp_boost_min != null) hpJson.put("min", this.hit_received_effect.hp_boost_min);
else hpJson.put("min", 0);
if (this.hit_received_effect.hp_boost_max != null) hpJson.put("max", this.hit_received_effect.hp_boost_max);
else hpJson.put("max", 0);
}
if (this.hit_received_effect.ap_boost_min != null || this.hit_received_effect.ap_boost_max != null) {
Map apJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseCurrentAP", apJson);
if (this.hit_received_effect.ap_boost_min != null) apJson.put("min", this.hit_received_effect.ap_boost_min);
else apJson.put("min", 0);
if (this.hit_received_effect.ap_boost_max != null) apJson.put("max", this.hit_received_effect.ap_boost_max);
else apJson.put("max", 0);
}
if (this.hit_received_effect.hp_boost_min_target != null || this.hit_received_effect.hp_boost_max_target != null) {
Map hpJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseAttackerCurrentHP", hpJson);
if (this.hit_received_effect.hp_boost_min_target != null) hpJson.put("min", this.hit_received_effect.hp_boost_min_target);
else hpJson.put("min", 0);
if (this.hit_received_effect.hp_boost_max_target != null) hpJson.put("max", this.hit_received_effect.hp_boost_max_target);
else hpJson.put("max", 0);
}
if (this.hit_received_effect.ap_boost_min_target != null || this.hit_received_effect.ap_boost_max_target != null) {
Map apJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseAttackerCurrentAP", apJson);
if (this.hit_received_effect.ap_boost_min_target != null) apJson.put("min", this.hit_received_effect.ap_boost_min_target);
else apJson.put("min", 0);
if (this.hit_received_effect.ap_boost_max_target != null) apJson.put("max", this.hit_received_effect.ap_boost_max_target);
else apJson.put("max", 0);
}
if (this.hit_received_effect.conditions_source != null) {
List conditionsSourceJson = new ArrayList();
hitReceivedEffectJson.put("conditionsSource", conditionsSourceJson);
for (TimedConditionEffect condition : this.hit_received_effect.conditions_source) {
Map conditionJson = new LinkedHashMap();
conditionsSourceJson.add(conditionJson);
if (condition.condition != null) {
conditionJson.put("condition", condition.condition.id);
} else if (condition.condition_id != null) {
conditionJson.put("condition", condition.condition_id);
}
if (condition.magnitude != null) conditionJson.put("magnitude", condition.magnitude);
if (condition.duration != null) conditionJson.put("duration", condition.duration);
if (condition.chance != null) conditionJson.put("chance", JSONElement.printJsonChance(condition.chance));
}
}
if (this.hit_received_effect.conditions_target != null) {
List conditionsTargetJson = new ArrayList();
hitReceivedEffectJson.put("conditionsTarget", conditionsTargetJson);
for (TimedConditionEffect condition : this.hit_received_effect.conditions_target) {
Map conditionJson = new LinkedHashMap();
conditionsTargetJson.add(conditionJson);
if (condition.condition != null) {
conditionJson.put("condition", condition.condition.id);
} else if (condition.condition_id != null) {
conditionJson.put("condition", condition.condition_id);
}
if (condition.magnitude != null) conditionJson.put("magnitude", condition.magnitude);
if (condition.duration != null) conditionJson.put("duration", condition.duration);
if (condition.chance != null) conditionJson.put("chance", JSONElement.printJsonChance(condition.chance));
}
}
}
if (this.kill_effect != null) {
Map killEffectJson = new LinkedHashMap();
if (this.category != null && this.category.action_type != null && this.category.action_type == ItemCategory.ActionType.equip) {

View File

@@ -38,11 +38,16 @@ public abstract class JSONElement extends GameDataElement {
for (Object obj : gameDataElements) {
Map jsonObj = (Map)obj;
String id = (String) jsonObj.get("id");
try {
if (id != null && id.equals(this.id )) {
this.parse(jsonObj);
this.state = State.parsed;
break;
}
}
catch(Exception e){
System.out.println("Error in ID: " + id);
}
}
} catch (FileNotFoundException e) {
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
@@ -53,6 +58,10 @@ public abstract class JSONElement extends GameDataElement {
} catch (ParseException e) {
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
e.printStackTrace();
} catch (IllegalArgumentException e) {
System.out.println(id);
Notification.addError("Error while parsing JSON file "+jsonFile.getAbsolutePath()+": "+e.getMessage());
e.printStackTrace();
} finally {
if (reader != null)
try {

View File

@@ -47,6 +47,8 @@ public class NPC extends JSONElement {
public Integer block_chance = null;
public Integer damage_resistance = null;
public HitEffect hit_effect = null;
public HitReceivedEffect hit_received_effect = null;
public DeathEffect death_effect = null;
//Available from linked state
public Dialogue dialogue = null;
@@ -70,17 +72,29 @@ public class NPC extends JSONElement {
protectSpawn,
wholeMap
}
public static class HitEffect {
public static class DeathEffect {
//Available from parsed state
public Integer hp_boost_min = null;
public Integer hp_boost_max = null;
public Integer ap_boost_min = null;
public Integer ap_boost_max = null;
public List<TimedConditionEffect> conditions_source = null;
}
public static class HitEffect extends DeathEffect {
//Available from parsed state
public List<TimedConditionEffect> conditions_target = null;
}
public static class HitReceivedEffect extends HitEffect {
//Available from parsed state
public Integer hp_boost_min_target = null;
public Integer hp_boost_max_target = null;
public Integer ap_boost_min_target = null;
public Integer ap_boost_max_target = null;
}
public static class TimedConditionEffect {
//Available from parsed state
public Integer magnitude = null;
@@ -224,6 +238,79 @@ public class NPC extends JSONElement {
}
}
Map hitReceivedEffect = (Map) npcJson.get("hitReceivedEffect");
if (hitReceivedEffect != null) {
this.hit_received_effect = new HitReceivedEffect();
if (hitReceivedEffect.get("increaseCurrentHP") != null) {
this.hit_received_effect.hp_boost_max = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentHP")).get("max")));
this.hit_received_effect.hp_boost_min = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentHP")).get("min")));
}
if (hitReceivedEffect.get("increaseCurrentAP") != null) {
this.hit_received_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentAP")).get("max")));
this.hit_received_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseCurrentAP")).get("min")));
}
if (hitReceivedEffect.get("increaseAttackerCurrentHP") != null) {
this.hit_received_effect.hp_boost_max_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentHP")).get("max")));
this.hit_received_effect.hp_boost_min_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentHP")).get("min")));
}
if (hitReceivedEffect.get("increaseAttackerCurrentAP") != null) {
this.hit_received_effect.ap_boost_max_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentAP")).get("max")));
this.hit_received_effect.ap_boost_min_target = JSONElement.getInteger((Number) (((Map)hitReceivedEffect.get("increaseAttackerCurrentAP")).get("min")));
}
List conditionsSourceJson = (List) hitReceivedEffect.get("conditionsSource");
if (conditionsSourceJson != null && !conditionsSourceJson.isEmpty()) {
this.hit_received_effect.conditions_source = new ArrayList<NPC.TimedConditionEffect>();
for (Object conditionJsonObj : conditionsSourceJson) {
Map conditionJson = (Map)conditionJsonObj;
TimedConditionEffect condition = new TimedConditionEffect();
condition.condition_id = (String) conditionJson.get("condition");
condition.magnitude = JSONElement.getInteger((Number) conditionJson.get("magnitude"));
condition.duration = JSONElement.getInteger((Number) conditionJson.get("duration"));
if (conditionJson.get("chance") != null) condition.chance = JSONElement.parseChance(conditionJson.get("chance").toString());
this.hit_received_effect.conditions_source.add(condition);
}
}
List conditionsTargetJson = (List) hitReceivedEffect.get("conditionsTarget");
if (conditionsTargetJson != null && !conditionsTargetJson.isEmpty()) {
this.hit_received_effect.conditions_target = new ArrayList<NPC.TimedConditionEffect>();
for (Object conditionJsonObj : conditionsTargetJson) {
Map conditionJson = (Map)conditionJsonObj;
TimedConditionEffect condition = new TimedConditionEffect();
condition.condition_id = (String) conditionJson.get("condition");
condition.magnitude = JSONElement.getInteger((Number) conditionJson.get("magnitude"));
condition.duration = JSONElement.getInteger((Number) conditionJson.get("duration"));
if (conditionJson.get("chance") != null) condition.chance = JSONElement.parseChance(conditionJson.get("chance").toString());
this.hit_received_effect.conditions_target.add(condition);
}
}
}
Map deathEffect = (Map) npcJson.get("deathEffect");
if (deathEffect != null) {
this.death_effect = new HitEffect();
if (deathEffect.get("increaseCurrentHP") != null) {
this.death_effect.hp_boost_max = JSONElement.getInteger((Number) (((Map)deathEffect.get("increaseCurrentHP")).get("max")));
this.death_effect.hp_boost_min = JSONElement.getInteger((Number) (((Map)deathEffect.get("increaseCurrentHP")).get("min")));
}
if (deathEffect.get("increaseCurrentAP") != null) {
this.death_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)deathEffect.get("increaseCurrentAP")).get("max")));
this.death_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)deathEffect.get("increaseCurrentAP")).get("min")));
}
List conditionsSourceJson = (List) deathEffect.get("conditionsSource");
if (conditionsSourceJson != null && !conditionsSourceJson.isEmpty()) {
this.death_effect.conditions_source = new ArrayList<NPC.TimedConditionEffect>();
for (Object conditionJsonObj : conditionsSourceJson) {
Map conditionJson = (Map)conditionJsonObj;
TimedConditionEffect condition = new TimedConditionEffect();
condition.condition_id = (String) conditionJson.get("condition");
condition.magnitude = JSONElement.getInteger((Number) conditionJson.get("magnitude"));
condition.duration = JSONElement.getInteger((Number) conditionJson.get("duration"));
if (conditionJson.get("chance") != null) condition.chance = JSONElement.parseChance(conditionJson.get("chance").toString());
this.death_effect.conditions_source.add(condition);
}
}
}
}
@Override
@@ -267,6 +354,24 @@ public class NPC extends JSONElement {
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.hit_received_effect != null && this.hit_received_effect.conditions_source != null) {
for (TimedConditionEffect ce : this.hit_received_effect.conditions_source) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.hit_received_effect != null && this.hit_received_effect.conditions_target != null) {
for (TimedConditionEffect ce : this.hit_received_effect.conditions_target) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
if (this.death_effect != null && this.death_effect.conditions_source != null) {
for (TimedConditionEffect ce : this.death_effect.conditions_source) {
if (ce.condition_id != null) ce.condition = proj.getActorCondition(ce.condition_id);
if (ce.condition != null) ce.condition.addBacklink(this);
}
}
this.state = State.linked;
}
@@ -343,6 +448,69 @@ public class NPC extends JSONElement {
}
}
}
if (this.hit_received_effect != null) {
clone.hit_received_effect = new HitReceivedEffect();
clone.hit_received_effect.ap_boost_max = this.hit_received_effect.ap_boost_max;
clone.hit_received_effect.ap_boost_min = this.hit_received_effect.ap_boost_min;
clone.hit_received_effect.hp_boost_max = this.hit_received_effect.hp_boost_max;
clone.hit_received_effect.hp_boost_min = this.hit_received_effect.hp_boost_min;
clone.hit_received_effect.ap_boost_max_target = this.hit_received_effect.ap_boost_max_target;
clone.hit_received_effect.ap_boost_min_target = this.hit_received_effect.ap_boost_min_target;
clone.hit_received_effect.hp_boost_max_target = this.hit_received_effect.hp_boost_max_target;
clone.hit_received_effect.hp_boost_min_target = this.hit_received_effect.hp_boost_min_target;
if (this.hit_received_effect.conditions_source != null) {
clone.hit_received_effect.conditions_source = new ArrayList<TimedConditionEffect>();
for (TimedConditionEffect c : this.hit_received_effect.conditions_source) {
TimedConditionEffect cclone = new TimedConditionEffect();
cclone.magnitude = c.magnitude;
cclone.condition_id = c.condition_id;
cclone.condition = c.condition;
cclone.chance = c.chance;
cclone.duration = c.duration;
if (cclone.condition != null) {
cclone.condition.addBacklink(clone);
}
clone.hit_received_effect.conditions_source.add(cclone);
}
}
if (this.hit_received_effect.conditions_target != null) {
clone.hit_received_effect.conditions_target = new ArrayList<TimedConditionEffect>();
for (TimedConditionEffect c : this.hit_received_effect.conditions_target) {
TimedConditionEffect cclone = new TimedConditionEffect();
cclone.magnitude = c.magnitude;
cclone.condition_id = c.condition_id;
cclone.condition = c.condition;
cclone.chance = c.chance;
cclone.duration = c.duration;
if (cclone.condition != null) {
cclone.condition.addBacklink(clone);
}
clone.hit_received_effect.conditions_target.add(cclone);
}
}
}
if (this.death_effect != null) {
clone.death_effect = new DeathEffect();
clone.death_effect.ap_boost_max = this.death_effect.ap_boost_max;
clone.death_effect.ap_boost_min = this.death_effect.ap_boost_min;
clone.death_effect.hp_boost_max = this.death_effect.hp_boost_max;
clone.death_effect.hp_boost_min = this.death_effect.hp_boost_min;
if (this.death_effect.conditions_source != null) {
clone.death_effect.conditions_source = new ArrayList<TimedConditionEffect>();
for (TimedConditionEffect c : this.death_effect.conditions_source) {
TimedConditionEffect cclone = new TimedConditionEffect();
cclone.magnitude = c.magnitude;
cclone.condition_id = c.condition_id;
cclone.condition = c.condition;
cclone.chance = c.chance;
cclone.duration = c.duration;
if (cclone.condition != null) {
cclone.condition.addBacklink(clone);
}
clone.death_effect.conditions_source.add(cclone);
}
}
}
clone.max_ap = this.max_ap;
clone.max_hp = this.max_hp;
clone.monster_class = this.monster_class;
@@ -478,6 +646,110 @@ public class NPC extends JSONElement {
}
}
}
if (this.hit_received_effect != null) {
Map hitReceivedEffectJson = new LinkedHashMap();
npcJson.put("hitReceivedEffect", hitReceivedEffectJson);
if (this.hit_received_effect.hp_boost_min != null || this.hit_received_effect.hp_boost_max != null) {
Map hpJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseCurrentHP", hpJson);
if (this.hit_received_effect.hp_boost_min != null) hpJson.put("min", this.hit_received_effect.hp_boost_min);
else hpJson.put("min", 0);
if (this.hit_received_effect.hp_boost_max != null) hpJson.put("max", this.hit_received_effect.hp_boost_max);
else hpJson.put("max", 0);
}
if (this.hit_received_effect.ap_boost_min != null || this.hit_received_effect.ap_boost_max != null) {
Map apJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseCurrentAP", apJson);
if (this.hit_received_effect.ap_boost_min != null) apJson.put("min", this.hit_received_effect.ap_boost_min);
else apJson.put("min", 0);
if (this.hit_received_effect.ap_boost_max != null) apJson.put("max", this.hit_received_effect.ap_boost_max);
else apJson.put("max", 0);
}
if (this.hit_received_effect.hp_boost_min_target != null || this.hit_received_effect.hp_boost_max_target != null) {
Map hpJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseAttackerCurrentHP", hpJson);
if (this.hit_received_effect.hp_boost_min_target != null) hpJson.put("min", this.hit_received_effect.hp_boost_min_target);
else hpJson.put("min", 0);
if (this.hit_received_effect.hp_boost_max_target != null) hpJson.put("max", this.hit_received_effect.hp_boost_max_target);
else hpJson.put("max", 0);
}
if (this.hit_received_effect.ap_boost_min_target != null || this.hit_received_effect.ap_boost_max_target != null) {
Map apJson = new LinkedHashMap();
hitReceivedEffectJson.put("increaseAttackerCurrentAP", apJson);
if (this.hit_received_effect.ap_boost_min_target != null) apJson.put("min", this.hit_received_effect.ap_boost_min_target);
else apJson.put("min", 0);
if (this.hit_received_effect.ap_boost_max_target != null) apJson.put("max", this.hit_received_effect.ap_boost_max_target);
else apJson.put("max", 0);
}
if (this.hit_received_effect.conditions_source != null) {
List conditionsSourceJson = new ArrayList();
hitReceivedEffectJson.put("conditionsSource", conditionsSourceJson);
for (TimedConditionEffect condition : this.hit_received_effect.conditions_source) {
Map conditionJson = new LinkedHashMap();
conditionsSourceJson.add(conditionJson);
if (condition.condition != null) {
conditionJson.put("condition", condition.condition.id);
} else if (condition.condition_id != null) {
conditionJson.put("condition", condition.condition_id);
}
if (condition.magnitude != null) conditionJson.put("magnitude", condition.magnitude);
if (condition.duration != null) conditionJson.put("duration", condition.duration);
if (condition.chance != null) conditionJson.put("chance", JSONElement.printJsonChance(condition.chance));
}
}
if (this.hit_received_effect.conditions_target != null) {
List conditionsTargetJson = new ArrayList();
hitReceivedEffectJson.put("conditionsTarget", conditionsTargetJson);
for (TimedConditionEffect condition : this.hit_received_effect.conditions_target) {
Map conditionJson = new LinkedHashMap();
conditionsTargetJson.add(conditionJson);
if (condition.condition != null) {
conditionJson.put("condition", condition.condition.id);
} else if (condition.condition_id != null) {
conditionJson.put("condition", condition.condition_id);
}
if (condition.magnitude != null) conditionJson.put("magnitude", condition.magnitude);
if (condition.duration != null) conditionJson.put("duration", condition.duration);
if (condition.chance != null) conditionJson.put("chance", JSONElement.printJsonChance(condition.chance));
}
}
}
if (this.death_effect != null) {
Map deathEffectJson = new LinkedHashMap();
npcJson.put("deathEffect", deathEffectJson);
if (this.death_effect.hp_boost_min != null || this.death_effect.hp_boost_max != null) {
Map hpJson = new LinkedHashMap();
deathEffectJson.put("increaseCurrentHP", hpJson);
if (this.death_effect.hp_boost_min != null) hpJson.put("min", this.death_effect.hp_boost_min);
else hpJson.put("min", 0);
if (this.death_effect.hp_boost_max != null) hpJson.put("max", this.death_effect.hp_boost_max);
else hpJson.put("max", 0);
}
if (this.death_effect.ap_boost_min != null || this.death_effect.ap_boost_max != null) {
Map apJson = new LinkedHashMap();
deathEffectJson.put("increaseCurrentAP", apJson);
if (this.death_effect.ap_boost_min != null) apJson.put("min", this.death_effect.ap_boost_min);
else apJson.put("min", 0);
if (this.death_effect.ap_boost_max != null) apJson.put("max", this.death_effect.ap_boost_max);
else apJson.put("max", 0);
}
if (this.death_effect.conditions_source != null) {
List conditionsSourceJson = new ArrayList();
deathEffectJson.put("conditionsSource", conditionsSourceJson);
for (TimedConditionEffect condition : this.death_effect.conditions_source) {
Map conditionJson = new LinkedHashMap();
conditionsSourceJson.add(conditionJson);
if (condition.condition != null) {
conditionJson.put("condition", condition.condition.id);
} else if (condition.condition_id != null) {
conditionJson.put("condition", condition.condition_id);
}
if (condition.magnitude != null) conditionJson.put("magnitude", condition.magnitude);
if (condition.duration != null) conditionJson.put("duration", condition.duration);
if (condition.chance != null) conditionJson.put("chance", JSONElement.printJsonChance(condition.chance));
}
}
}
return npcJson;
}

View File

@@ -30,22 +30,6 @@ public class Quest extends JSONElement {
public Integer visible_in_log = null;
public List<QuestStage> 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;
}
@@ -113,19 +99,16 @@ public class Quest extends JSONElement {
public void parse(Map questJson) {
this.visible_in_log = JSONElement.getInteger((Number) questJson.get("showInLog"));
List questStagesJson = (List) questJson.get("stages");
this.stages = new ArrayList<QuestStage>();
if (questStagesJson != null && !questStagesJson.isEmpty()) {
this.stages = new ArrayList<QuestStage>();
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<Quest.QuestStage>();
clone.stages = new ArrayList<QuestStage>();
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;
}
}

View File

@@ -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();
}
}

View File

@@ -26,10 +26,13 @@ public class Requirement extends JSONElement {
countedItemTypes.add(RequirementType.inventoryRemove);
countedItemTypes.add(RequirementType.inventoryKeep);
countedItemTypes.add(RequirementType.usedItem);
countedItemTypes.add(RequirementType.wear);
countedItemTypes.add(RequirementType.wearRemove);
COMPATIBLE_TYPES.put(RequirementType.inventoryRemove, countedItemTypes);
COMPATIBLE_TYPES.put(RequirementType.inventoryKeep, countedItemTypes);
COMPATIBLE_TYPES.put(RequirementType.usedItem, countedItemTypes);
COMPATIBLE_TYPES.put(RequirementType.wear, countedItemTypes);
COMPATIBLE_TYPES.put(RequirementType.wearRemove, countedItemTypes);
}
//Available from parsed state
@@ -53,12 +56,82 @@ public class Requirement extends JSONElement {
usedItem,
spentGold,
consumedBonemeals,
hasActorCondition
hasActorCondition,
factionScore,
random,
factionScoreEquals,
wearRemove,
date,
dateEquals,
time,
timeEquals
}
public enum SkillID {
weaponChance
,weaponDmg
,barter
,dodge
,barkSkin
,moreCriticals
,betterCriticals
,speed // Raises max ap
,coinfinder
,moreExp
,cleave // +10ap on kill
,eater // +1hp per kill
,fortitude // +N hp per levelup
,evasion // increase successful flee chance & reduce chance of monster attack
,regeneration // +N hp per round
,lowerExploss
,magicfinder
,resistanceMental // lowers chance to get negative active conditions by monsters (Mental like Dazed)
,resistancePhysical // lowers chance to get negative active conditions by monsters (Physical Capacity like Minor fatigue)
,resistanceBlood // lowers chance to get negative active conditions by monsters (Blood Disorder like Weak Poison)
,shadowBless
,sporeImmunity
,crit1 // lowers atk ability
,crit2 // lowers def ability ,rejuvenation // Reduces magnitudes of conditions
,rejuvenation // Reduces magnitudes of conditions
,taunt // Causes AP loss of attackers that miss
,concussion // AC loss for monsters with (AC-BC)>N
,weaponProficiencyDagger
,weaponProficiency1hsword
,weaponProficiency2hsword
,weaponProficiencyAxe
,weaponProficiencyBlunt
,weaponProficiencyUnarmed
,weaponProficiencyPole
,armorProficiencyShield
,armorProficiencyUnarmored
,armorProficiencyLight
,armorProficiencyHeavy
,fightstyleDualWield
,fightstyle2hand
,fightstyleWeaponShield
,specializationDualWield
,specialization2hand
,specializationWeaponShield
}
@Override
public String getDesc() {
return ((negated != null && negated) ? "NOT " : "")+required_obj_id+(required_value == null ? "" : ":"+required_value.toString());
String obj_id = "";
if (required_obj_id != null)
{
obj_id = required_obj_id;
if (type != null && type == RequirementType.random){
obj_id = " Chance " + obj_id + (required_obj_id.contains("/") ? "" : "%");
}
else {
obj_id += ":";
}
}
return ((negated != null && negated) ? "NOT " : "")
+(type == null ? "" : type.toString()+":")
+obj_id
+(required_value == null ? "" : required_value.toString());
}
@Override
@@ -104,6 +177,7 @@ public class Requirement extends JSONElement {
case inventoryRemove:
case usedItem:
case wear:
case wearRemove:
this.required_obj = proj.getItem(required_obj_id);
break;
case killedMonster:
@@ -112,11 +186,24 @@ 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:
case spentGold:
case timerElapsed:
case factionScore:
case factionScoreEquals:
case random:
case date:
case dateEquals:
case time:
case timeEquals:
break;
}
if (this.required_obj != null) this.required_obj.addBacklink((GameDataElement) this.parent);
@@ -135,6 +222,7 @@ public class Requirement extends JSONElement {
clone.state = this.state;
clone.required_obj_id = this.required_obj_id;
clone.required_value = this.required_value;
clone.negated = this.negated;
clone.required_obj = this.required_obj;
clone.type = this.type;
if (clone.required_obj != null && parent != null) {
@@ -150,6 +238,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() {
@@ -162,6 +256,12 @@ public class Requirement extends JSONElement {
required_obj_id = null;
required_value = null;
}
if(destType==RequirementType.random)
{
required_obj_id = "50/100";
}
type = destType;
}

View File

@@ -19,26 +19,29 @@ public class KeyArea extends MapObject {
String requireType = obj.getProperties().getProperty("requireType");
String requireId = obj.getProperties().getProperty("requireId");
String requireValue = obj.getProperties().getProperty("requireValue");
if (requireId == null) {
String requireNegation = obj.getProperties().getProperty("requireNegation");
oldSchoolRequirement = false;
if (requireType == null) {
String[] fields = obj.getName().split(":");
if (fields.length == 2) {
requireType = Requirement.RequirementType.questProgress.toString();
requireValue = fields[1];
requireId = fields[0];
oldSchoolRequirement = true;
} else if (fields.length == 3) {
requireValue = fields[2];
requireType = fields[0];
requireId = fields[1];
oldSchoolRequirement = true;
}
oldSchoolRequirement = true;
} else {
oldSchoolRequirement = false;
}
requirement = new Requirement();
if (requireType != null) requirement.type = Requirement.RequirementType.valueOf(requireType);
requirement.required_obj_id = requireId;
if (requireValue != null) requirement.required_value = Integer.parseInt(requireValue);
if (requireNegation != null) requirement.negated = Boolean.parseBoolean(requireNegation);
requirement.state = GameDataElement.State.parsed;
}
@Override
@@ -76,7 +79,7 @@ public class KeyArea extends MapObject {
}
if (requirement != null) {
if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) {
tmxObject.setName(requirement.required_obj_id+":"+Integer.toString(requirement.required_value));
tmxObject.setName(requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)));
} else {
if (requirement.type != null) {
tmxObject.getProperties().setProperty("requireType", requirement.type.toString());
@@ -89,13 +92,16 @@ public class KeyArea extends MapObject {
if (requirement.required_value != null) {
tmxObject.getProperties().setProperty("requireValue", requirement.required_value.toString());
}
if (requirement.negated != null) {
tmxObject.getProperties().setProperty("requireNegation", Boolean.toString(requirement.negated));
}
}
}
}
public void updateNameFromRequirementChange() {
if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) {
name = requirement.required_obj_id+":"+Integer.toString(requirement.required_value);
name = (requirement.negated != null && requirement.negated) ? "NOT " : "" + requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value));
} else if (oldSchoolRequirement) {
int i = 0;
String futureName = requirement.type.toString() + "#" + Integer.toString(i);

View File

@@ -12,39 +12,38 @@ import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class ReplaceArea extends MapObject {
public Requirement requirement = null;
public boolean oldSchoolRequirement = true;
public boolean oldSchoolRequirement = false;
public List<ReplaceArea.Replacement> replacements = null;
public ReplaceArea(tiled.core.MapObject obj) {
// String requireType = obj.getProperties().getProperty("requireType");
String requireType = obj.getProperties().getProperty("requireType");
String requireId = obj.getProperties().getProperty("requireId");
String requireValue = obj.getProperties().getProperty("requireValue");
if (requireId == null) {
String requireNegation = obj.getProperties().getProperty("requireNegation");
if (requireType == null) {
String[] fields = obj.getName().split(":");
if (fields.length == 2) {
// requireType = Requirement.RequirementType.questProgress.toString();
requireType = Requirement.RequirementType.questProgress.toString();
requireValue = fields[1];
requireId = fields[0];
oldSchoolRequirement = true;
} /*else if (fields.length == 3) {
requireValue = fields[2];
requireType = fields[0];
requireId = fields[1];
}*/
oldSchoolRequirement = true;
} else {
oldSchoolRequirement = false;
}
requirement = new Requirement();
//Replace areas only support questProgress requirements ATM
//requirement.type = Requirement.RequirementType.valueOf(requireType);
requirement.type = Requirement.RequirementType.questProgress;
if (requireType != null) requirement.type = Requirement.RequirementType.valueOf(requireType);
requirement.required_obj_id = requireId;
if (requireValue != null) requirement.required_value = Integer.parseInt(requireValue);
if (requireNegation != null) requirement.negated = Boolean.parseBoolean(requireNegation);
requirement.state = GameDataElement.State.parsed;
for (Object s : obj.getProperties().keySet()) {
if (!TMXMap.isPaintedLayerName(s.toString())) continue;
if (replacements == null) replacements = new ArrayList<ReplaceArea.Replacement>();
replacements.add(new Replacement(s.toString(), obj.getProperties().getProperty(s.toString())));
}
@@ -94,9 +93,11 @@ public class ReplaceArea extends MapObject {
}
if (requirement != null) {
if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) {
tmxObject.setName(requirement.required_obj_id+":"+Integer.toString(requirement.required_value));
tmxObject.setName(requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)));
} else {
tmxObject.getProperties().setProperty("requireType", requirement.type.toString());
if (requirement.type != null) {
tmxObject.getProperties().setProperty("requireType", requirement.type.toString());
}
if (requirement.required_obj != null) {
tmxObject.getProperties().setProperty("requireId", requirement.required_obj.id);
} else if (requirement.required_obj_id != null) {
@@ -105,6 +106,9 @@ public class ReplaceArea extends MapObject {
if (requirement.required_value != null) {
tmxObject.getProperties().setProperty("requireValue", requirement.required_value.toString());
}
if (requirement.negated != null) {
tmxObject.getProperties().setProperty("requireNegation", Boolean.toString(requirement.negated));
}
}
}
}
@@ -112,7 +116,7 @@ public class ReplaceArea extends MapObject {
//Don't use yet !
public void updateNameFromRequirementChange() {
if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) {
name = requirement.required_obj_id+":"+Integer.toString(requirement.required_value);
name = (requirement.negated != null && requirement.negated) ? "NOT " : "" + requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value));
} else if (oldSchoolRequirement) {
int i = 0;
String futureName = requirement.type.toString() + "#" + Integer.toString(i);

View File

@@ -11,8 +11,9 @@ import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class SpawnArea extends MapObject {
public int quantity = 1;
public int spawnchance = 10;
public int respawnSpeed = 10;
public boolean active = true;
public boolean ignoreAreas = false;
public String spawngroup_id;
public List<NPC> spawnGroup = new ArrayList<NPC>();
@@ -20,12 +21,15 @@ public class SpawnArea extends MapObject {
if (obj.getProperties().getProperty("quantity") != null) {
this.quantity = Integer.parseInt(obj.getProperties().getProperty("quantity"));
}
if (obj.getProperties().getProperty("spawnchance") != null) {
this.spawnchance = Integer.parseInt(obj.getProperties().getProperty("spawnchance"));
if (obj.getProperties().getProperty("respawnspeed") != null) {
this.respawnSpeed = Integer.parseInt(obj.getProperties().getProperty("respawnspeed"));
}
if (obj.getProperties().getProperty("active") != null) {
this.active = Boolean.parseBoolean(obj.getProperties().getProperty("active"));
}
if (obj.getProperties().getProperty("ignoreAreas") != null) {
this.ignoreAreas = Boolean.parseBoolean(obj.getProperties().getProperty("ignoreAreas"));
}
if (obj.getProperties().getProperty("spawngroup") != null) {
this.spawngroup_id = obj.getProperties().getProperty("spawngroup");
} else if (obj.getName() != null ){
@@ -78,12 +82,14 @@ public class SpawnArea extends MapObject {
if (quantity != 1) {
tmxObject.getProperties().setProperty("quantity", Integer.toString(quantity));
}
if (spawnchance != 10) {
tmxObject.getProperties().setProperty("spawnchance", Integer.toString(spawnchance));
if (respawnSpeed != 10) {
tmxObject.getProperties().setProperty("respawnspeed", Integer.toString(respawnSpeed));
}
if (!this.active) {
tmxObject.getProperties().setProperty("active", Boolean.toString(active));
}
if (this.ignoreAreas) {
tmxObject.getProperties().setProperty("ignoreAreas", Boolean.toString(ignoreAreas));
}
}
}

View File

@@ -38,6 +38,7 @@ public class TMXMap extends GameDataElement {
public static final String GROUND_LAYER_NAME = "Ground";
public static final String OBJECTS_LAYER_NAME = "Objects";
public static final String ABOVE_LAYER_NAME = "Above";
public static final String TOP_LAYER_NAME = "Top";
public static final String WALKABLE_LAYER_NAME = "Walkable";
public enum ColorFilter {
@@ -257,7 +258,7 @@ public class TMXMap extends GameDataElement {
if (getDataType() == GameSource.Type.source) {
writer.writeMap(tmxMap, baos, tmxFile.getAbsolutePath());
} else {
writer.writeMap(tmxMap, baos, getProject().baseContent.gameMaps.mapFolder.getAbsolutePath()+File.separator+"placeholder.tmx");
writer.writeMap(tmxMap, baos, ((TMXMapSet)this.parent).mapFolder.getAbsolutePath()+File.separator+"placeholder.tmx");
}
} catch (Exception e) {
Notification.addError("Error while converting map "+getDesc()+" to XML: "+e.getMessage());
@@ -273,11 +274,12 @@ public class TMXMap extends GameDataElement {
public void save() {
if (writable) {
String xml = toXml();
try {
//TODO: check in fileutils, to test the workspace's filesystem once at startup, and figure out how many of these can occur, instead of hard-coded '2'
dismissNextChangeNotif += 2;
FileWriter w = new FileWriter(tmxFile);
w.write(toXml());
w.write(xml);
w.close();
this.state = State.saved;
changedOnDisk = false;
@@ -397,6 +399,7 @@ public class TMXMap extends GameDataElement {
return GROUND_LAYER_NAME.equalsIgnoreCase(name) ||
OBJECTS_LAYER_NAME.equalsIgnoreCase(name) ||
ABOVE_LAYER_NAME.equalsIgnoreCase(name) ||
TOP_LAYER_NAME.equalsIgnoreCase(name) ||
WALKABLE_LAYER_NAME.equalsIgnoreCase(name);
}

View File

@@ -15,6 +15,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.swing.tree.TreeNode;
@@ -92,29 +93,31 @@ public class TMXMapSet implements ProjectTreeNode {
});
if (source.type == GameSource.Type.created | source.type == GameSource.Type.altered) {
final Path folderPath = Paths.get(mapFolder.getAbsolutePath());
Thread watcher = new Thread("Map folder watcher for "+source.type) {
Thread watcher = new Thread("Map folder watcher for "+getProject().name+"/"+source.type) {
public void run() {
WatchService watchService;
while(getProject().open) {
try {
watchService = FileSystems.getDefault().newWatchService();
WatchKey watchKey = folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
/*WatchKey watchKey = */folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey wk;
validService: while(getProject().open) {
wk = watchService.take();
for (WatchEvent<?> event : wk.pollEvents()) {
Path changed = (Path) event.context();
String name = changed.getFileName().toString();
String id = name.substring(0, name.length() - 4);
TMXMap map = getMap(id);
if (map != null) {
map.mapChangedOnDisk();
wk = watchService.poll(10, TimeUnit.SECONDS);
if (wk != null) {
for (WatchEvent<?> event : wk.pollEvents()) {
Path changed = (Path) event.context();
String name = changed.getFileName().toString();
String id = name.substring(0, name.length() - 4);
TMXMap map = getMap(id);
if (map != null) {
map.mapChangedOnDisk();
}
}
if(!wk.reset()) {
watchService.close();
break validService;
}
}
if(!wk.reset()) {
watchService.close();
break validService;
}
}
} catch (IOException e) {

View File

@@ -35,6 +35,7 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.Project;
@@ -222,6 +223,7 @@ public class Worldmap extends ArrayList<WorldmapSegment> implements ProjectTreeN
for (WorldmapSegment segment : this) {
root.appendChild(segment.toXmlElement(doc));
segment.state = GameDataElement.State.saved;
}
saveDocToFile(doc, worldmapFile);

View File

@@ -23,7 +23,9 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
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.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
@@ -32,6 +34,8 @@ public class WorldmapSegment extends GameDataElement {
private static final long serialVersionUID = 2658610076889592723L;
public static final String TEMP_LABEL_KEY = "ATCS_INTERNAL_TEMPORARY_KEY_FOR_LABEL";
public int segmentX;
public int segmentY;
public Map<String, Point> mapLocations = new LinkedHashMap<String, Point>();
@@ -102,8 +106,37 @@ public class WorldmapSegment extends GameDataElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
boolean modified = false;
if (newOne == null && writable) {
//A referenced map may have been deleted.
if (mapLocations.containsKey(oldOne.id)) {
mapLocations.remove(oldOne.id);
modified = true;
}
List<String> deprecatedLabels = new ArrayList<String>();
for (String label : labelledMaps.keySet()) {
if (labelledMaps.get(label).contains(oldOne.id)) {
labelledMaps.get(label).remove(oldOne.id);
modified = true;
if (labelledMaps.get(label).isEmpty()) {
deprecatedLabels.add(label);
}
}
}
for (String label : deprecatedLabels) {
labelledMaps.remove(label);
labels.remove(label);
}
}
oldOne.removeBacklink(this);
if(newOne != null) newOne.addBacklink(this);
if (modified) {
this.state = GameDataElement.State.modified;
childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(this);
}
}
@Override
@@ -154,6 +187,7 @@ public class WorldmapSegment extends GameDataElement {
map.setAttribute("x", Integer.toString(mapLocations.get(s).x + segmentX));
map.setAttribute("y", Integer.toString(mapLocations.get(s).y + segmentY));
for (String label : labelledMaps.keySet()) {
if (TEMP_LABEL_KEY.equals(label)) continue;
if (labelledMaps.get(label).contains(s)) {
map.setAttribute("area", label);
}
@@ -161,7 +195,9 @@ public class WorldmapSegment extends GameDataElement {
element.appendChild(map);
}
for (NamedArea area : labels.values()) {
for (String key : labels.keySet()) {
if (TEMP_LABEL_KEY.equals(key)) continue;
NamedArea area = labels.get(key);
Element namedArea = doc.createElement("namedarea");
namedArea.setAttribute("id", area.id);
namedArea.setAttribute("name", area.name);

View File

@@ -14,6 +14,7 @@ import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.tree.TreeNode;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
@@ -174,7 +175,7 @@ public class Spritesheet extends GameDataElement {
}
Image result = getImage(index);
if (result == null) return null;
result = result.getScaledInstance(16, 16, BufferedImage.SCALE_SMOOTH);
result = result.getScaledInstance((int)(16*ATContentStudio.SCALING), (int)(16*ATContentStudio.SCALING), Image.SCALE_SMOOTH);
cache_icon.put(index, result);
return result;
}

View File

@@ -0,0 +1,89 @@
package com.gpl.rpg.atcontentstudio.model.tools.i18n;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class PoPotWriter {
Map<String, List<String>> stringsResources = new LinkedHashMap<String, List<String>>();
Map<String, String> translations = new LinkedHashMap<String, String>();
File f;
public static void writePoFile(Map<String, List<String>> stringsResources, Map<String, String> translations, File destination) {
try {
Writer fw = new OutputStreamWriter(new FileOutputStream(destination), StandardCharsets.UTF_8);
if (translations.get("") != null) {
fw.write(translations.get(""));
writeEndOfEntry(fw);
}
if (translations.get("translator-credits") != null) {
List<String> refs = new LinkedList<String>();
refs.add("[none]");
writeReferences(fw, refs);
writeMsgId(fw, "translator-credits");
writeMsgStr(fw, translations.get("translator-credits"));
writeEndOfEntry(fw);
}
for (String msg : stringsResources.keySet()) {
writeReferences(fw, stringsResources.get(msg));
writeMsgId(fw, msg);
writeMsgStr(fw, translations.get(msg));
writeEndOfEntry(fw);
}
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writePotFile(Map<String, List<String>> stringsResources, File destination) {
try {
FileWriter fw = new FileWriter(destination);
for (String msg : stringsResources.keySet()) {
writeReferences(fw, stringsResources.get(msg));
writeMsgId(fw, msg);
writeMsgStr(fw, "");
writeEndOfEntry(fw);
}
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeReferences(Writer w, List<String> references) throws IOException {
for (String ref : references) {
w.write("#: ");
w.write(ref);
w.write("\n");
}
}
private static void writeMsgId(Writer w, String msg) throws IOException {
w.write("msgid \"");
w.write(msg);
w.write("\"\n");
}
private static void writeMsgStr(Writer w, String translation) throws IOException {
w.write("msgstr \"");
w.write(translation == null ? "" : translation);
w.write("\"\n");
}
private static void writeEndOfEntry(Writer w) throws IOException {
w.write("\n");
}
}

View File

@@ -0,0 +1,310 @@
package com.gpl.rpg.atcontentstudio.model.tools.i18n;
import java.io.File;
import java.io.FileFilter;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.swing.JOptionPane;
import com.gpl.rpg.atcontentstudio.model.Project;
import net.launchpad.tobal.poparser.POEntry;
import net.launchpad.tobal.poparser.POFile;
import net.launchpad.tobal.poparser.POParser;
/**
*
* @author Kevin
*
* To use this, paste the following script in the beanshell console of ATCS.
* Don't forget to change the project number to suit your needs.
*
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.tools.i18n.PotGenerator;
import com.gpl.rpg.atcontentstudio.model.tools.i18n.PotComparator;
proj = Workspace.activeWorkspace.projects.get(7);
PotGenerator.generatePotFileForProject(proj);
comp = new PotComparator(proj);
comp.compare();
comp.updatePoFiles(proj);
*
*
*
*/
public class PotComparator {
Map<String, List<String>> stringsResourcesNew = new LinkedHashMap<String, List<String>>();
Map<String, String> resourcesStringsNew = new LinkedHashMap<String, String>();
Map<String, List<String>> stringsResourcesOld = new LinkedHashMap<String, List<String>>();
Map<String, String> resourcesStringsOld = new LinkedHashMap<String, String>();
Map<String, String> msgIdToReplace = new LinkedHashMap<String, String>();
List<String> msgIdToReview = new LinkedList<String>();
List<String> msgIdOutdated = new LinkedList<String>();
public PotComparator(Project proj) {
POParser parser = new POParser();
POFile newPot = parser.parseFile(new File(proj.alteredContent.baseFolder.getAbsolutePath()+File.separator+"english.pot"));
if (newPot == null) {
System.err.println("Cannot locate new english.pot file at "+proj.alteredContent.baseFolder.getAbsolutePath()+File.separator);
}
extractFromPoFile(newPot, stringsResourcesNew, resourcesStringsNew);
POFile oldPot = parser.parseFile(new File(proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translation"+File.separator+"english.pot"));
if (oldPot == null) {
System.err.println("Cannot locate old english.pot file at "+proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translations"+File.separator);
}
extractFromPoFile(oldPot, stringsResourcesOld, resourcesStringsOld);
}
private void extractFromPoFile(POFile po, Map<String, List<String>> stringsResources, Map<String, String> resourcesStrings) {
for (POEntry entry : po.getEntryArray()) {
Vector<String> resources = entry.getStringsByType(POEntry.StringType.REFERENCE);
Vector<String> msgids = entry.getStringsByType(POEntry.StringType.MSGID);
if (resources == null || resources.size() == 0 || msgids == null || msgids.size() == 0) continue;
String msgid = msgids.get(0);
if (msgids.size() > 1) {
for (int i = 1; i < msgids.size(); i++) {
msgid += msgids.get(i);
}
}
if (msgid.contains("\\n")) {
msgid = msgid.replaceAll("\\\\n", "\\\\n\"\n\"");
msgid = "\"\n\""+msgid;
}
for (String resLine : resources) {
String[] resArray = resLine.split(" ");
for (String res : resArray) {
resourcesStrings.put(res, msgid);
if (stringsResources.get(msgid) == null) {
stringsResources.put(msgid, new LinkedList<String>());
}
stringsResources.get(msgid).add(res);
}
}
}
}
public void compare() {
for (String oldRes : resourcesStringsOld.keySet()) {
String newString = resourcesStringsNew.get(oldRes);
String oldString = resourcesStringsOld.get(oldRes);
if (newString != null) {
if (!newString.equals(oldString)) {
List<String> allOldResources = stringsResourcesOld.get(oldString);
List<String> allNewResources = stringsResourcesNew.get(oldString);
StringBuffer sb = new StringBuffer();
sb.append("---------------------------------------------\n");
sb.append("--- TYPO CHECK ------------------------------\n");
sb.append("---------------------------------------------\n");
sb.append("String at: "+oldRes+"\n");
if (allOldResources.size() > 1) {
sb.append("Also present at:\n");
for (String res : allOldResources) {
if (!res.equals(oldRes)) {
sb.append("- "+res+"\n");
}
}
}
if (allNewResources != null) {
sb.append("Still present at: \n");
for (String res : allNewResources) {
sb.append("- "+res+"\n");
}
}
sb.append("Was : \""+oldString+"\"\n");
sb.append("Now : \""+newString+"\"\n");
System.out.println(sb.toString());
showTypoDialog(oldString, newString, sb.toString());
}
} else {
List<String> allOldResources = stringsResourcesOld.get(oldString);
List<String> allNewResources = stringsResourcesNew.get(oldString);
if (allOldResources.size() >= 1) {
System.out.println("---------------------------------------------");
System.out.println("--- REMOVED RESOURCE ------------------------");
System.out.println("---------------------------------------------");
System.out.println("String at: "+oldRes);
if (allOldResources.size() > 1) {
System.out.println("And also at:");
for (String res : allOldResources) {
if (!res.equals(oldRes)) {
System.out.println("- "+res);
}
}
}
System.out.println("Was: \""+oldString+"\"");
if (allNewResources == null) {
System.out.println("Absent from new.");
} else {
System.out.println("Still present at: ");
for (String res : allNewResources) {
System.out.println("- "+res);
}
}
}
}
}
removedStrings: for (String oldString : stringsResourcesOld.keySet()) {
if (stringsResourcesNew.get(oldString) == null) {
List<String> allOldResources = stringsResourcesOld.get(oldString);
if (allOldResources.size() >= 1) {
if (allOldResources.size() > 0) {
for (String res : allOldResources) {
String newString = resourcesStringsNew.get(res);
if (newString != null) {
continue removedStrings;
}
}
}
System.out.println("---------------------------------------------");
System.out.println("--- REMOVED STRING --------------------------");
System.out.println("---------------------------------------------");
System.out.println("String: \""+oldString+"\"");
if (allOldResources.size() > 0) {
System.out.println("Was at:");
for (String res : allOldResources) {
System.out.println("- "+res);
}
}
System.out.println("This string is absent from the new file, and its attached resources are missing too.");
}
}
}
}
private void showTypoDialog(String oldMsg, String newMsg, String checkReport) {
String typo = "Typo";
String review = "Review";
String outdated = "Outdated";
String none = "None";
Object[] options = new Object[] {typo, review, outdated, none};
int result = JOptionPane.showOptionDialog(null, checkReport, "Choose action", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, typo);
if (result < 0 || result >= options.length) {
System.out.println("No decision");
return;
}
System.out.println("Decision: "+options[result]);
if (options[result] != none) {
msgIdToReplace.put(oldMsg, newMsg);
if (options[result] == review) {
msgIdToReview.add(newMsg);
} else if (options[result] == outdated) {
msgIdOutdated.add(newMsg);
}
}
}
public void updatePoFiles(Project proj) {
File poFolder = new File(proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translation");
File[] poFiles = poFolder.listFiles(new FileFilter() {
@Override
public boolean accept(File arg0) {
return arg0.isFile() && arg0.getName().endsWith(".po");
}
});
for (File f : poFiles) {
updatePoFile(proj, f);
}
}
private void updatePoFile(Project proj, File f) {
POParser parser = new POParser();
POFile poFile = parser.parseFile(f);
Map<String, String> translations = new LinkedHashMap<String, String>();
//Collect existing translations
if (poFile.getHeader() != null) {
Vector<String> msgstrs = poFile.getHeader().getStringsByType(POEntry.StringType.HEADER);
String header = "";
if (!msgstrs.isEmpty()) {
if (msgstrs.size() == 1) {
header = msgstrs.get(0);
} else {
for (String msgstr : msgstrs) {
header += msgstr;
header += "\n";
}
}
}
translations.put("", header);
}
for (POEntry entry : poFile.getEntryArray()) {
Vector<String> msgids = entry.getStringsByType(POEntry.StringType.MSGID);
Vector<String> msgstrs = entry.getStringsByType(POEntry.StringType.MSGSTR);
if (msgids == null || msgids.size() == 0) continue;
String msgid = msgids.get(0);
if (msgids.size() > 1) {
for (int i = 1; i < msgids.size(); i++) {
msgid += msgids.get(i);
}
}
if (msgid.contains("\\n")) {
msgid = msgid.replaceAll("\\\\n", "\\\\n\"\n\"");
msgid = "\"\n\""+msgid;
}
String translation = "";
if (!msgstrs.isEmpty()) {
if (msgstrs.size() == 1) {
translation = msgstrs.get(0);
} else {
for (String msgstr : msgstrs) {
translation += msgstr;
}
}
if (translation.contains("\\n")) {
translation = translation.replaceAll("\\\\n", "\\\\n\"\n\"");
translation = "\"\n\""+translation;
}
}
translations.put(msgid, translation);
}
//Patch data
for (String oldId : msgIdToReplace.keySet()) {
String newId = msgIdToReplace.get(oldId);
if (translations.containsKey(oldId)) {
String trans = translations.get(oldId);
translations.remove(oldId);
translations.put(newId, trans);
}
}
for (String msgid : msgIdToReview) {
if (translations.containsKey(msgid)) {
String trans = translations.get(msgid);
if (trans != null && trans.length() >= 1) translations.put(msgid, "[REVIEW]"+trans);
}
}
for (String msgid : msgIdOutdated) {
if (translations.containsKey(msgid)) {
String trans = translations.get(msgid);
if (trans != null && trans.length() >= 1) translations.put(msgid, "[OUTDATED]"+trans);
}
}
PoPotWriter.writePoFile(stringsResourcesNew, translations, new File(proj.alteredContent.baseFolder.getAbsolutePath()+File.separator+f.getName()));
}
}

View File

@@ -0,0 +1,100 @@
package com.gpl.rpg.atcontentstudio.model.tools.i18n;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
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.WorldmapSegment;
public class PotGenerator {
public static void generatePotFileForProject(Project proj) {
Map<String, List<String>> stringsResources = new LinkedHashMap<String, List<String>>();
Map<String, String> resourcesStrings = new LinkedHashMap<String, String>();
GameSource gsrc = proj.baseContent;
for (ActorCondition ac : gsrc.gameData.actorConditions) {
pushString(stringsResources, resourcesStrings, ac.display_name, getPotContextComment(ac));
}
for (Dialogue d : gsrc.gameData.dialogues ) {
pushString(stringsResources, resourcesStrings, d.message, getPotContextComment(d));
if (d.replies == null) continue;
for (Dialogue.Reply r : d.replies) {
if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT) ) {
pushString(stringsResources, resourcesStrings, r.text, getPotContextComment(d)+":"+d.replies.indexOf(r));
}
}
}
for (ItemCategory ic : gsrc.gameData.itemCategories) {
pushString(stringsResources, resourcesStrings, ic.name, getPotContextComment(ic));
}
for (Item i : gsrc.gameData.items) {
pushString(stringsResources, resourcesStrings, i.name, getPotContextComment(i));
pushString(stringsResources, resourcesStrings, i.description, getPotContextComment(i)+":description");
}
for (NPC npc : gsrc.gameData.npcs ) {
pushString(stringsResources, resourcesStrings, npc.name, getPotContextComment(npc));
}
for (Quest q : gsrc.gameData.quests) {
if (q.visible_in_log != null && q.visible_in_log != 0) {
pushString(stringsResources, resourcesStrings, q.name, getPotContextComment(q));
for (QuestStage qs : q.stages) {
pushString(stringsResources, resourcesStrings, qs.log_text, getPotContextComment(q)+":"+Integer.toString(qs.progress));
}
}
}
for (WorldmapSegment ws : gsrc.worldmap) {
for (WorldmapSegment.NamedArea area : ws.labels.values()) {
pushString(stringsResources, resourcesStrings, area.name, gsrc.worldmap.worldmapFile.getName()+":"+ws.id+":"+area.id);
}
}
File f = new File(proj.alteredContent.baseFolder, "english.pot");
PoPotWriter.writePotFile(stringsResources, f);
}
private static void pushString (Map<String, List<String>> stringsResources, Map<String, String> resourcesStrings, String translatableString, String resourceIdentifier) {
if (translatableString == null) return;
if (translatableString.length() == 0) return;
if (translatableString.contains("\"")) {
translatableString = translatableString.replaceAll("\"", "\\\\\"");
}
if (translatableString.contains("\n")) {
translatableString = translatableString.replaceAll("\n", "\\\\n\"\n\"");
translatableString = "\"\n\""+translatableString;
}
resourcesStrings.put(resourceIdentifier, translatableString);
List<String> resourceIdentifiers = stringsResources.get(translatableString);
if (resourceIdentifiers == null) {
resourceIdentifiers = new LinkedList<String>();
stringsResources.put(translatableString, resourceIdentifiers);
}
resourceIdentifiers.add(resourceIdentifier);
}
private static String getPotContextComment(JSONElement e) {
return e.jsonFile.getName()+":"+e.id;
}
}

View File

@@ -0,0 +1,381 @@
package com.gpl.rpg.atcontentstudio.model.tools.resoptimizer;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import org.json.simple.JSONArray;
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
import com.gpl.rpg.atcontentstudio.utils.FileUtils;
import com.whoischarles.util.json.Minify;
import com.whoischarles.util.json.Minify.UnterminatedCommentException;
import com.whoischarles.util.json.Minify.UnterminatedRegExpLiteralException;
import com.whoischarles.util.json.Minify.UnterminatedStringLiteralException;
import tiled.core.TileSet;
import tiled.io.TMXMapWriter;
/**
*
* @author Kevin
*
* To use this, paste the following script in the beanshell console of ATCS.
* Don't forget to change the project number to suit your needs.
*
import com.gpl.rpg.atcontentstudio.model.tools.resoptimizer.ResourcesCompactor;
import com.gpl.rpg.atcontentstudio.model.Workspace;
proj = Workspace.activeWorkspace.projects.get(0);
new ResourcesCompactor(proj).compactData();
*
*/
public class ResourcesCompactor {
public static String DEFAULT_REL_PATH_IN_PROJECT = "compressed"+File.separator;
private Project proj;
private File baseFolder;
private List<CompressedSpritesheet> compressedSpritesheets = new LinkedList<CompressedSpritesheet>();
private List<File> preservedSpritesheets = new LinkedList<File>();
private Map<SpritesheetId, SpritesheetId> spritesRelocationForObjects = new LinkedHashMap<SpritesheetId, SpritesheetId>();
private Integer currentSpritesheetIndexForObjects = 0;
private CompressedSpritesheet currentSpritesheetForObjects = null;
private Map<SpritesheetId, SpritesheetId> spritesRelocationForMaps = new LinkedHashMap<SpritesheetId, SpritesheetId>();
private Map<SpritesheetId, CompressedSpritesheet> spritesheetsBySidForMaps = new LinkedHashMap<SpritesheetId, CompressedSpritesheet>();
private Integer currentSpritesheetIndexForMaps = 0;
private CompressedSpritesheet currentSpritesheetForMaps = null;
public ResourcesCompactor(Project proj) {
this.proj = proj;
this.baseFolder = new File(proj.baseFolder, DEFAULT_REL_PATH_IN_PROJECT);
if (!baseFolder.exists()) baseFolder.mkdirs();
}
public void compactData() {
compactJsonData();
for(CompressedSpritesheet cs : compressedSpritesheets) {
cs.drawFile();
}
for (File preserved : preservedSpritesheets) {
FileUtils.copyFile(preserved, new File(baseFolder.getAbsolutePath()+File.separator+DEFAULT_DRAWABLE_REL_PATH+File.separator+preserved.getName()));
}
compactMaps();
}
public void compactJsonData() {
final List<File> filesCovered = new LinkedList<File>();
File folder = new File(baseFolder.getAbsolutePath()+File.separator+GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!folder.exists()) folder.mkdirs();
for (ActorCondition ac : proj.baseContent.gameData.actorConditions) {
if (filesCovered.contains(ac.jsonFile)) continue;
File currentFile = ac.jsonFile;
filesCovered.add(currentFile);
List<Map> dataToSave = new ArrayList<Map>();
for (ActorCondition acond : proj.baseContent.gameData.actorConditions) {
if (!acond.jsonFile.equals(currentFile)) continue;
Map json = acond.toJson();
json.put("iconID", convertObjectSprite(acond.icon_id).toStringID());
dataToSave.add(json);
}
File target = new File(folder, ac.jsonFile.getName());
writeJson(dataToSave, target);
}
for (Item it : proj.baseContent.gameData.items) {
if (filesCovered.contains(it.jsonFile)) continue;
File currentFile = it.jsonFile;
filesCovered.add(currentFile);
List<Map> dataToSave = new ArrayList<Map>();
for (Item item : proj.baseContent.gameData.items) {
if (!item.jsonFile.equals(currentFile)) continue;
Map json = item.toJson();
json.put("iconID", convertObjectSprite(item.icon_id).toStringID());
dataToSave.add(json);
}
File target = new File(folder, it.jsonFile.getName());
writeJson(dataToSave, target);
}
for (NPC np : proj.baseContent.gameData.npcs) {
if (filesCovered.contains(np.jsonFile)) continue;
File currentFile = np.jsonFile;
filesCovered.add(currentFile);
List<Map> dataToSave = new ArrayList<Map>();
for (NPC npc : proj.baseContent.gameData.npcs) {
if (!npc.jsonFile.equals(currentFile)) continue;
Map json = npc.toJson();
if (proj.getImage(npc.icon_id).getWidth(null) == TILE_WIDTH_IN_PIXELS || proj.getImage(npc.icon_id).getHeight(null) == TILE_HEIGHT_IN_PIXELS) {
json.put("iconID", convertObjectSprite(npc.icon_id).toStringID());
}
dataToSave.add(json);
}
File target = new File(folder, np.jsonFile.getName());
writeJson(dataToSave, target);
}
File[] remainingFiles = proj.baseContent.gameData.baseFolder.listFiles(new FileFilter() {
@Override
public boolean accept(File arg0) {
return arg0.getName().endsWith(".json") && !filesCovered.contains(arg0);
}
});
for (File source : remainingFiles) {
File target = new File(folder, source.getName());
minifyJson(source, target);
}
}
private Minify jsonMinifier = new Minify();
private void writeJson(List<Map> dataToSave, File target) {
StringWriter writer = new JsonPrettyWriter();
try {
JSONArray.writeJSONString(dataToSave, writer);
} catch (IOException e) {
//Impossible with a StringWriter
}
String toWrite = writer.toString();
try {
FileWriter w = new FileWriter(target);
w.write(jsonMinifier.minify(toWrite));
w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void minifyJson(File source, File target) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
FileInputStream fis = new FileInputStream(source);
jsonMinifier.minify(fis, baos);
FileWriter w = new FileWriter(target);
w.write(baos.toString());
w.close();
} catch (IOException e) {
e.printStackTrace();
} catch (UnterminatedRegExpLiteralException e) {
e.printStackTrace();
} catch (UnterminatedCommentException e) {
e.printStackTrace();
} catch (UnterminatedStringLiteralException e) {
e.printStackTrace();
}
}
private void compactMaps() {
for (TMXMap map : proj.baseContent.gameMaps.tmxMaps) {
TMXMap clone = map.clone();
for (GameDataElement gde : clone.getBacklinks()) {
gde.removeBacklink(clone);
}
clone.getBacklinks().clear();
tiled.core.Map tmx = clone.tmxMap;
compactMap(tmx, map.id);
clone.tmxMap = null;
clone.groups.clear();
clone = null;
}
}
private void compactMap(tiled.core.Map tmx, String name) {
File target = new File(baseFolder.getAbsolutePath()+File.separator+TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE+File.separator+name+".tmx");
if (!target.getParentFile().exists()) target.getParentFile().mkdirs();
Map<tiled.core.Tile, SpritesheetId> localConvertions = new LinkedHashMap<tiled.core.Tile, SpritesheetId>();
List<CompressedSpritesheet> usedSpritesheets = new LinkedList<CompressedSpritesheet>();
List<tiled.core.TileSet> toRemove = new LinkedList<TileSet>();
for (tiled.core.TileSet ts : tmx.getTileSets()) {
if (!ts.getName().equalsIgnoreCase("map_dynamic_placeholders")) {
toRemove.add(ts);
}
}
for (tiled.core.TileLayer layer : tmx.getTileLayers()) {
for (int x = 0; x < layer.getWidth(); x++) {
for (int y = 0; y < layer.getHeight(); y++) {
tiled.core.Tile tile = layer.getTileAt(x, y);
if (tile != null && !tile.getTileSet().getName().equalsIgnoreCase("map_dynamic_placeholders")) {
SpritesheetId sid = convertMapSprite(SpritesheetId.toStringID(tile.getTileSet().getName(), tile.getId()));
localConvertions.put(tile, sid);
if (!usedSpritesheets.contains(spritesheetsBySidForMaps.get(sid))) {
usedSpritesheets.add(spritesheetsBySidForMaps.get(sid));
}
}
}
}
}
Map<CompressedSpritesheet, tiled.core.TileSet> csToTs = new LinkedHashMap<CompressedSpritesheet, tiled.core.TileSet>();
for (CompressedSpritesheet cs : usedSpritesheets) {
cs.drawFile();
tiled.core.TileSet ts = new tiled.core.TileSet();
csToTs.put(cs, ts);
tiled.util.BasicTileCutter cutter = new tiled.util.BasicTileCutter(TILE_WIDTH_IN_PIXELS, TILE_HEIGHT_IN_PIXELS, 0, 0);
try {
ts.importTileBitmap(cs.f.getAbsolutePath(), cutter);
} catch (IOException e) {
e.printStackTrace();
}
ts.setName(cs.prefix+Integer.toString(cs.index));
//ts.setSource("../drawable/"+ts.getName()+TILESHEET_SUFFIX);
tmx.addTileset(ts);
}
for (tiled.core.TileLayer layer : tmx.getTileLayers()) {
for (tiled.core.Tile tile : localConvertions.keySet()) {
SpritesheetId sid = localConvertions.get(tile);
layer.replaceTile(tile, csToTs.get(spritesheetsBySidForMaps.get(sid)).getTile(sid.offset));
}
}
for (tiled.core.TileSet ts : toRemove) {
tmx.removeTileset(ts);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TMXMapWriter writer = new TMXMapWriter();
writer.settings.layerCompressionMethod = TMXMapWriter.Settings.LAYER_COMPRESSION_METHOD_ZLIB;
try {
writer.writeMap(tmx, baos, target.getAbsolutePath());
String xml = baos.toString();
FileWriter w = new FileWriter(target);
w.write(xml);
w.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private SpritesheetId convertObjectSprite(String originalSpriteId) {
if (spritesRelocationForObjects.containsKey(SpritesheetId.getInstance(originalSpriteId))) {
return spritesRelocationForObjects.get(SpritesheetId.getInstance(originalSpriteId));
} else if (currentSpritesheetForObjects == null || !currentSpritesheetForObjects.hasFreeSlot()) {
currentSpritesheetForObjects = new CompressedSpritesheet(TILESHEET_PREFIX_FOR_OBJECTS, currentSpritesheetIndexForObjects);
compressedSpritesheets.add(currentSpritesheetForObjects);
currentSpritesheetIndexForObjects++;
}
SpritesheetId sid = currentSpritesheetForObjects.addSprite(originalSpriteId);
spritesRelocationForObjects.put(SpritesheetId.getInstance(originalSpriteId), sid);
return sid;
}
private SpritesheetId convertMapSprite(String originalSpriteId) {
if (spritesRelocationForMaps.containsKey(SpritesheetId.getInstance(originalSpriteId))) {
return spritesRelocationForMaps.get(SpritesheetId.getInstance(originalSpriteId));
} else if (currentSpritesheetForMaps == null || !currentSpritesheetForMaps.hasFreeSlot()) {
currentSpritesheetForMaps = new CompressedSpritesheet(TILESHEET_PREFIX_FOR_MAPS, currentSpritesheetIndexForMaps);
compressedSpritesheets.add(currentSpritesheetForMaps);
currentSpritesheetIndexForMaps++;
}
SpritesheetId sid = currentSpritesheetForMaps.addSprite(originalSpriteId);
spritesRelocationForMaps.put(SpritesheetId.getInstance(originalSpriteId), sid);
spritesheetsBySidForMaps.put(sid, currentSpritesheetForMaps);
return sid;
}
private static final int TILESHEET_WIDTH_IN_SPRITES = 8;
private static final int TILESHEET_HEIGHT_IN_SPRITES = 8;
private static final int TILE_WIDTH_IN_PIXELS = 32;
private static final int TILE_HEIGHT_IN_PIXELS = 32;
private static final String TILESHEET_PREFIX_FOR_OBJECTS = "obj_";
private static final String TILESHEET_PREFIX_FOR_MAPS = "map_";
private static final String TILESHEET_SUFFIX = ".png";
private static final String DEFAULT_DRAWABLE_REL_PATH = SpriteSheetSet.DEFAULT_REL_PATH_IN_SOURCE;
private class CompressedSpritesheet {
String prefix;
int index;
File f;
boolean mustDraw = true;
int nextFreeSlot = 0;
String[] originalSpritesId = new String[TILESHEET_WIDTH_IN_SPRITES * TILESHEET_HEIGHT_IN_SPRITES];
public CompressedSpritesheet(String prefix, int index) {
this.prefix = prefix;
this.index = index;
File folder = new File(ResourcesCompactor.this.baseFolder.getAbsolutePath()+File.separator+DEFAULT_DRAWABLE_REL_PATH);
if (!folder.exists()) folder.mkdirs();
this.f = new File(folder, prefix+Integer.toString(index)+TILESHEET_SUFFIX);
}
public boolean hasFreeSlot() {
return nextFreeSlot < TILESHEET_WIDTH_IN_SPRITES * TILESHEET_HEIGHT_IN_SPRITES;
}
public SpritesheetId addSprite(String spriteId) {
mustDraw = true;
originalSpritesId[nextFreeSlot] = spriteId;
nextFreeSlot++;
return SpritesheetId.getInstance(prefix+Integer.toString(index), nextFreeSlot - 1);
}
public void drawFile() {
if (!mustDraw) return;
BufferedImage img = new BufferedImage(TILESHEET_WIDTH_IN_SPRITES * TILE_WIDTH_IN_PIXELS, TILESHEET_HEIGHT_IN_SPRITES * TILE_HEIGHT_IN_PIXELS, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D)img.getGraphics();
Color transparent = new Color(0, 0, 0, 0);
g.setColor(transparent);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
for (int i = 0; i < nextFreeSlot; i++) {
g.drawImage(
proj.getImage(originalSpritesId[i]),
(i % TILESHEET_WIDTH_IN_SPRITES) * TILE_WIDTH_IN_PIXELS,
(i / TILESHEET_WIDTH_IN_SPRITES) * TILE_HEIGHT_IN_PIXELS,
TILE_WIDTH_IN_PIXELS,
TILE_HEIGHT_IN_PIXELS,
null);
}
try {
ImageIO.write(img, "png", f);
mustDraw = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,38 @@
package com.gpl.rpg.atcontentstudio.model.tools.resoptimizer;
import java.util.LinkedHashMap;
import java.util.Map;
public class SpritesheetId {
static Map<String, SpritesheetId> instancesCache = new LinkedHashMap<String, SpritesheetId>();
String tileset;
int offset;
static SpritesheetId getInstance(String id) {
String[] values = id.split(":");
return getInstance(values[0], Integer.parseInt(values[1]));
}
static SpritesheetId getInstance(String tilesetId, int offset) {
if (!instancesCache.containsKey(toStringID(tilesetId, offset))) {
SpritesheetId instance = new SpritesheetId(tilesetId, offset);
instancesCache.put(instance.toStringID(), instance);
}
return instancesCache.get(toStringID(tilesetId, offset));
}
private SpritesheetId(String tileset, int offset) {
this.tileset = tileset;
this.offset = offset;
}
public String toStringID() {
return toStringID(tileset, offset);
}
static String toStringID(String tileset, int offset) {
return tileset+":"+Integer.toString(offset);
}
}

View File

@@ -167,6 +167,9 @@ public class WriterModeData extends GameDataElement {
this.id = (String) json.get("id");
this.index = ((Number)json.get("index")).intValue();
this.id_prefix = (String) json.get("id_prefix");
if (threadsNextIndex.get(id_prefix) == null || threadsNextIndex.get(id_prefix) <= index) {
threadsNextIndex.put(id_prefix, index+1);
}
this.text = (String) json.get("text");
this.dialogue_id = (String) json.get("dialogue");
if (json.get("begin") != null && ((Boolean)json.get("begin"))) begin = this;
@@ -541,6 +544,7 @@ public class WriterModeData extends GameDataElement {
nodesById.put(dialogue.getID(), dialogue);
}
}
this.state = State.parsed;
}
@@ -557,6 +561,11 @@ public class WriterModeData extends GameDataElement {
this.parse();
}
if (this.state == State.parsed) {
for (String prefix : threadsNextIndex.keySet()) {
while (getProject().getDialogue(prefix+threadsNextIndex.get(prefix)) != null) {
threadsNextIndex.put(prefix, threadsNextIndex.get(prefix)+1);
}
}
for (WriterDialogue dialogue : nodesById.values()) {
if (dialogue.dialogue_id != null) {
dialogue.dialogue = getProject().getDialogue(dialogue.dialogue_id);
@@ -571,32 +580,34 @@ public class WriterModeData extends GameDataElement {
}
}
//TODO Seriously, this is failure-prone by design. Can't do much better though...
List<Dialogue.Reply> linked = new ArrayList<Dialogue.Reply>(dialogue.dialogue.replies.size());
if (dialogue.dialogue != null && dialogue.dialogue.replies != null) {
//Try to hook to existing replies... not as easy when there's no ID.
Dialogue.Reply best = null;
int score, maxScore = 0;
for (Dialogue.Reply dReply : dialogue.dialogue.replies) {
//Never link twice to the same...
if (linked.contains(dReply)) continue;
score = 0;
//Arbitrary values... hopefully this gives good results.
//Same target gives good hope of preserving at least the structure.
if (dReply.next_phrase_id != null && dReply.next_phrase_id.equals(reply.next_dialogue_id)) score +=50;
//Same text is almost as good as an ID, but there may be duplicates due to requirements system...
if (dReply.text != null && dReply.text.equals(reply.text)) score +=40;
//Same slot in the list. That's not so bad if all else fails, and could help sort duplicates with same text.
if (dialogue.dialogue.replies.indexOf(dReply) == dialogue.replies.indexOf(reply)) score +=20;
//Both have null text. It's not much, but it's something....
if (dReply.text == null && reply.text == null) score += 10;
if (score > maxScore) {
maxScore = score;
best = dReply;
}
}
if (maxScore > 0) {
reply.reply = best;
linked.add(best);
if (dialogue.dialogue != null) {
List<Dialogue.Reply> linked = new ArrayList<Dialogue.Reply>(dialogue.dialogue.replies.size());
if (dialogue.dialogue != null && dialogue.dialogue.replies != null) {
//Try to hook to existing replies... not as easy when there's no ID.
Dialogue.Reply best = null;
int score, maxScore = 0;
for (Dialogue.Reply dReply : dialogue.dialogue.replies) {
//Never link twice to the same...
if (linked.contains(dReply)) continue;
score = 0;
//Arbitrary values... hopefully this gives good results.
//Same target gives good hope of preserving at least the structure.
if (dReply.next_phrase_id != null && dReply.next_phrase_id.equals(reply.next_dialogue_id)) score +=50;
//Same text is almost as good as an ID, but there may be duplicates due to requirements system...
if (dReply.text != null && dReply.text.equals(reply.text)) score +=40;
//Same slot in the list. That's not so bad if all else fails, and could help sort duplicates with same text.
if (dialogue.dialogue.replies.indexOf(dReply) == dialogue.replies.indexOf(reply)) score +=20;
//Both have null text. It's not much, but it's something....
if (dReply.text == null && reply.text == null) score += 10;
if (score > maxScore) {
maxScore = score;
best = dReply;
}
}
if (maxScore > 0) {
reply.reply = best;
linked.add(best);
}
}
}
}

View File

@@ -109,7 +109,7 @@ public class WriterModeDataSet implements ProjectTreeNode, Serializable {
@Override
public String getDesc() {
return (needsSaving() ? "*" : "")+"Dialogue sketchs";
return (needsSaving() ? "*" : "")+"Dialogue sketches";
}
@Override

View File

@@ -26,7 +26,9 @@ public class AboutEditor extends Editor {
private static final long serialVersionUID = 6230549148222457139L;
public static final String WELCOME_STRING =
"<html><body>" +
"<html><head>" +
"<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\" />" +
"</head><body>" +
"<table><tr valign=\"top\">" +
"<td><img src=\""+ATContentStudio.class.getResource("/com/gpl/rpg/atcontentstudio/img/atcs_border_banner.png")+"\"/></td>" +
"<td><font size=+1>Welcome to "+ATContentStudio.APP_NAME+" "+ATContentStudio.APP_VERSION+"</font><br/>" +
@@ -35,22 +37,24 @@ public class AboutEditor extends Editor {
"<b>Right click on the left area or use the \"File\" menu to create a project.</b><br/>" +
"<br/>" +
"Play <a href=\"https://play.google.com/store/apps/details?id=com.gpl.rpg.AndorsTrail\">Andor's Trail</a> for free on your Android device.<br/>" +
"Visit <a href=\"http://andorstrail.com/\">the official forum</a> to give or receive help.<br/>" +
"Visit <a href=\"https://andorstrail.com/\">the official forum</a> to give or receive help.<br/>" +
"Open the project's <a href=\"https://github.com/Zukero/andors-trail/\">GitHub project page</a> to check out the game's source code.<br/>" +
"<br/>" +
"For content creation help, make sure to use the following resources:<br/>" +
"<a href=\"http://andorstrail.com/viewtopic.php?f=6&t=4560\">The contribution guide on the forums</a><br/>" +
"<a href=\"http://andorstrail.com/wiki/doku.php?id=andors_trail_wiki:developer_section\">The developer section of the Andor's Trail wiki</a><br/>" +
"<a href=\"https://andorstrail.com/viewtopic.php?f=6&t=4560\">The contribution guide on the forums</a><br/>" +
"<a href=\"https://andorstrail.com/wiki/doku.php?id=andors_trail_wiki:developer_section\">The developer section of the Andor's Trail wiki</a><br/>" +
"<a href=\"https://docs.google.com/document/d/1BwWD1tLgPcmA2bwudrVnOc6f2dkPLFCjWdn7tXlIp5g\">The design outline document on Google Drive/Docs</a><br/>" +
"<br/>" +
"<font size=+1>Credits:</font><br/>" +
"<br/>" +
"Author: <a href=\"http://andorstrail.com/memberlist.php?mode=viewprofile&u=2875\">Zukero</a><br/>" +
"Author: <a href=\"https://andorstrail.com/memberlist.php?mode=viewprofile&u=2875\">Zukero</a><br/>" +
"Licence: <a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">GPL v3</a><br/>" +
"Sources are included in this package and on <a href=\"https://github.com/Zukero/ATCS\">GitHub</a>.<br/>" +
"<br/>" +
"Contributors: <br/>" +
"Quentin Delvallet<br/>" +
"Žižkin<br/>" +
"Gonk<br/>" +
"<br/>" +
"This project uses the following libraries:<br/>" +
"<a href=\"http://code.google.com/p/json-simple/\">JSON.simple</a> by Yidong Fang & Chris Nokleberg.<br/>" +
@@ -78,6 +82,12 @@ public class AboutEditor extends Editor {
"<a href=\"https://jsoup.org/\">jsoup</a> by Jonathan Hedley<br/>" +
"License: <a href=\"https://jsoup.org/license\">MIT License</a><br/>" +
"<br/>" +
"A slightly modified version of <a href=\"https://launchpad.net/po-parser\">General PO Parser</a> by Bal<61>zs T<>th<br/>" +
"License: <a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">GPL v3</a><br/>" +
"<br/>" +
"A slightly modified version of <a href=\"www.whoischarles.com\">Minify.java</a> by Charles Bihis<br/>" +
"License: <a href=\"https://github.com/charlesbihis/minify#license\">Douglas Crockford variant of MIT License</a><br/>" +
"<br/>" +
"See the tabs below to find the full license text for each of these.<br/>" +
"<br/>" +
"The Windows installer was created with:<br/>" +
@@ -129,6 +139,8 @@ public class AboutEditor extends Editor {
editorTabsHolder.add("BeanShell License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.LGPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("SipHash for Java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.siphash-zackehh.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("jsoup License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.jsoup.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("General PO Parser License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("Minify.java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.minify.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
}

View File

@@ -7,6 +7,7 @@ import java.util.Map;
import javax.imageio.ImageIO;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
public class DefaultIcons {
@@ -74,6 +75,14 @@ public class DefaultIcons {
private static String FOLDER_AT_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_at_open.png";
public static Image getATOpenImage() { return getImage(FOLDER_AT_OPEN_RES); }
public static Image getATOpenIcon() { return getIcon(FOLDER_AT_OPEN_RES); }
private static String FOLDER_BOOKMARK_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_bookmark_closed.png";
public static Image getBookmarkClosedImage() { return getImage(FOLDER_BOOKMARK_CLOSED_RES); }
public static Image getBookmarkClosedIcon() { return getIcon(FOLDER_BOOKMARK_CLOSED_RES); }
private static String FOLDER_BOOKMARK_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_bookmark_open.png";
public static Image getBookmarkOpenImage() { return getImage(FOLDER_BOOKMARK_OPEN_RES); }
public static Image getBookmarkOpenIcon() { return getIcon(FOLDER_BOOKMARK_OPEN_RES); }
private static String TILED_ICON_RES = "/com/gpl/rpg/atcontentstudio/img/tiled-icon.png";
public static Image getTiledIconImage() { return getImage(TILED_ICON_RES); }
@@ -107,6 +116,10 @@ public class DefaultIcons {
public static Image getNPCImage() { return getImage(NPC_RES); }
public static Image getNPCIcon() { return getIcon(NPC_RES); }
private static String BONEMEAL_RES = "/com/gpl/rpg/atcontentstudio/img/bonemeal.png";
public static Image getBonemealImage() { return getImage(BONEMEAL_RES); }
public static Image getBonemealIcon() { return getIcon(BONEMEAL_RES); }
private static String NPC_CLOSE_RES = "/com/gpl/rpg/atcontentstudio/img/npc_close.png";
public static Image getNPCCloseImage() { return getImage(NPC_CLOSE_RES); }
public static Image getNPCCloseIcon() { return getIcon(NPC_CLOSE_RES); }
@@ -130,6 +143,14 @@ public class DefaultIcons {
private static String GOLD_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_coins.png";
public static Image getGoldImage() { return getImage(GOLD_RES); }
public static Image getGoldIcon() { return getIcon(GOLD_RES); }
private static String SKILL_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_skill.png";
public static Image getSkillImage() { return getImage(SKILL_RES); }
public static Image getSkillIcon() { return getIcon(SKILL_RES); }
private static String IMMUNITY_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_immunity.png";
public static Image getImmunityImage() { return getImage(IMMUNITY_RES); }
public static Image getImmunityIcon() { return getIcon(IMMUNITY_RES); }
private static String ITEM_CATEGORY_RES = "/com/gpl/rpg/atcontentstudio/img/equip_weapon.png";
public static Image getItemCategoryImage() { return getImage(ITEM_CATEGORY_RES); }
@@ -227,10 +248,30 @@ public class DefaultIcons {
public static Image getCreateTileLayerImage() { return getImage(CREATE_TILE_LAYER_RES); }
public static Image getCreateTileLayerIcon() { return getIcon(CREATE_TILE_LAYER_RES); }
private static String LABEL_RES = "/com/gpl/rpg/atcontentstudio/img/label.png";
public static Image getLabelImage() { return getImage(LABEL_RES); }
public static Image getLabelIcon() { return getIcon(LABEL_RES); }
private static String ZOOM_RES = "/com/gpl/rpg/atcontentstudio/img/zoom.png";
public static Image getZoomImage() { return getImage(ZOOM_RES); }
public static Image getZoomIcon() { return getIcon(ZOOM_RES); }
private static String TIMER_RES = "/com/gpl/rpg/atcontentstudio/img/timer.png";
public static Image getTimerImage() { return getImage(TIMER_RES); }
public static Image getTimerIcon() { return getIcon(TIMER_RES); }
private static String DATE_RES = "/com/gpl/rpg/atcontentstudio/img/date.png";
public static Image getDateImage() { return getImage(DATE_RES); }
public static Image getDateIcon() { return getIcon(DATE_RES); }
private static String TIME_RES = "/com/gpl/rpg/atcontentstudio/img/date.png";
public static Image getTimeImage() { return getImage(TIME_RES); }
public static Image getTimeIcon() { return getIcon(TIME_RES); }
private static String ALIGNMENT_RES = "/com/gpl/rpg/atcontentstudio/img/alignment.png";
public static Image getAlignmentImage() { return getImage(ALIGNMENT_RES); }
public static Image getAlignmentIcon() { return getIcon(ALIGNMENT_RES); }
private static String STATUS_RED_RES = "/com/gpl/rpg/atcontentstudio/img/status_red.png";
public static Image getStatusRedImage() { return getImage(STATUS_RED_RES); }
public static Image getStatusRedIcon() { return getIcon(STATUS_RED_RES); }
@@ -240,7 +281,7 @@ public class DefaultIcons {
public static Image getStatusOrangeIcon() { return getIcon(STATUS_ORANGE_RES); }
private static String STATUS_GREEN_RES = "/com/gpl/rpg/atcontentstudio/img/status_green.png";
public static Image getStatusGreenImage() { return getImage(STATUS_GREEN_RES); }
public static Image getStatusGreenImage() { return getImage(STATUS_GREEN_RES); }
public static Image getStatusGreenIcon() { return getIcon(STATUS_GREEN_RES); }
private static String STATUS_BLUE_RES = "/com/gpl/rpg/atcontentstudio/img/status_blue.png";
@@ -251,6 +292,14 @@ public class DefaultIcons {
public static Image getStatusUnknownImage() { return getImage(STATUS_UNKNOWN_RES); }
public static Image getStatusUnknownIcon() { return getIcon(STATUS_UNKNOWN_RES); }
private static String BOOKMARK_INACTIVE = "/com/gpl/rpg/atcontentstudio/img/bookmark_inactive.png";
public static Image getBookmarkInactiveImage() { return getImage(BOOKMARK_INACTIVE); }
public static Image getBookmarkInactiveIcon() { return getIcon(BOOKMARK_INACTIVE); }
private static String BOOKMARK_ACTIVE = "/com/gpl/rpg/atcontentstudio/img/bookmark_active.png";
public static Image getBookmarkActiveImage() { return getImage(BOOKMARK_ACTIVE); }
public static Image getBookmarkActiveIcon() { return getIcon(BOOKMARK_ACTIVE); }
private static Image getImage(String res) {
if (imageCache.get(res) == null) {
@@ -267,7 +316,7 @@ public class DefaultIcons {
private static Image getIcon(String res) {
if (iconCache.get(res) == null) {
Image icon = getImage(res).getScaledInstance(16, 16, Image.SCALE_SMOOTH);
Image icon = getImage(res).getScaledInstance((int)(16*ATContentStudio.SCALING), (int)(16*ATContentStudio.SCALING), Image.SCALE_SMOOTH);
iconCache.put(res, icon);
}
return iconCache.get(res);

View File

@@ -63,6 +63,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 +119,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 +271,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);
@@ -311,11 +315,15 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
// }
public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) {
return addIntegerField(pane, label, initialValue, 0, allowNegatives, editable, listener);
}
public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, Integer defaultValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) {
JPanel tfPane = new JPanel();
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
JLabel tfLabel = new JLabel(label);
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : 0, allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1));
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : defaultValue.intValue(), allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1));
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
spinner.setEnabled(editable);
((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
@@ -340,6 +348,138 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return spinner;
}
private static final String percent = "%";
private static final String ratio = "x/y";
public static JComponent addChanceField(JPanel pane, String label, String initialValue, String defaultValue, boolean editable, final FieldUpdateListener listener) {
int defaultChance = 1;
int defaultMaxChance = 100;
if (defaultValue != null) {
if (defaultValue.contains("/")) {
int c = defaultValue.indexOf('/');
try { defaultChance = Integer.parseInt(defaultValue.substring(0, c)); } catch (NumberFormatException nfe) {};
try { defaultMaxChance = Integer.parseInt(defaultValue.substring(c+1)); } catch (NumberFormatException nfe) {};
} else {
try { defaultChance = Integer.parseInt(defaultValue); } catch (NumberFormatException nfe) {};
}
}
boolean currentFormIsRatio = true;
int chance = defaultChance;
int maxChance = defaultMaxChance;
if (initialValue != null) {
if (initialValue.contains("/")) {
int c = initialValue.indexOf('/');
try { chance = Integer.parseInt(initialValue.substring(0, c)); } catch (NumberFormatException nfe) {};
try { maxChance = Integer.parseInt(initialValue.substring(c+1)); } catch (NumberFormatException nfe) {};
} else {
try {
chance = Integer.parseInt(initialValue);
currentFormIsRatio = false;
} catch (NumberFormatException nfe) {};
}
}
final JPanel tfPane = new JPanel();
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
JLabel tfLabel = new JLabel(label);
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JComboBox<String> entryTypeBox = new JComboBox<String>(new String[] {percent, ratio});
if (currentFormIsRatio) {
entryTypeBox.setSelectedItem(ratio);
} else {
entryTypeBox.setSelectedItem(percent);
}
entryTypeBox.setEnabled(editable);
tfPane.add(entryTypeBox, JideBoxLayout.FIX);
/////////////////////////////////////////////////////////////////////////////////////////////////// make sure "chance" is between 1 and 100. If lower than 1 get 1. If higher than 100, get chance/maxChance * 100... Then do the same with defaultChance, in case no value exist.
final SpinnerNumberModel percentModel = new SpinnerNumberModel(initialValue != null ? ((chance > 1 ? chance : 1) < 100 ? chance : (chance * 100 / maxChance)) : ((defaultChance > 1 ? defaultChance : 1) < 100 ? defaultChance : (defaultChance * 100 / defaultMaxChance)) , 1, 100, 1);
final SpinnerNumberModel ratioChanceModel = new SpinnerNumberModel(initialValue != null ? chance : defaultChance, 1, Integer.MAX_VALUE, 1);
final JSpinner chanceSpinner = new JSpinner(currentFormIsRatio ? ratioChanceModel : percentModel);
if (!currentFormIsRatio) ((JSpinner.DefaultEditor)chanceSpinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
chanceSpinner.setEnabled(editable);
((DefaultFormatter)((NumberEditor)chanceSpinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
tfPane.add(chanceSpinner, JideBoxLayout.FLEXIBLE);
final JLabel ratioLabel = new JLabel("/");
tfPane.add(ratioLabel, JideBoxLayout.FIX);
final JSpinner maxChanceSpinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? maxChance : defaultMaxChance, 1, Integer.MAX_VALUE, 1));
((JSpinner.DefaultEditor)maxChanceSpinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
maxChanceSpinner.setEnabled(editable);
((DefaultFormatter)((NumberEditor)maxChanceSpinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
tfPane.add(maxChanceSpinner, JideBoxLayout.FLEXIBLE);
if (!currentFormIsRatio) {
ratioLabel.setVisible(false);
maxChanceSpinner.setVisible(false);
tfPane.revalidate();
tfPane.repaint();
}
final JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
tfPane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(editable);
pane.add(tfPane, JideBoxLayout.FIX);
entryTypeBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (entryTypeBox.getSelectedItem() == percent) {
int chance = ((Integer)chanceSpinner.getValue());
int maxChance = ((Integer)maxChanceSpinner.getValue());
chance *= 100;
chance /= maxChance;
chance = Math.max(0, Math.min(100, chance));
chanceSpinner.setModel(percentModel);
chanceSpinner.setValue(chance);
((JSpinner.DefaultEditor)chanceSpinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
ratioLabel.setVisible(false);
maxChanceSpinner.setVisible(false);
tfPane.revalidate();
tfPane.repaint();
listener.valueChanged(chanceSpinner, chanceSpinner.getValue().toString());
} else if (entryTypeBox.getSelectedItem() == ratio) {
int chance = ((Integer)chanceSpinner.getValue());
chanceSpinner.setModel(ratioChanceModel);
chanceSpinner.setValue(chance);
maxChanceSpinner.setValue(100);
ratioLabel.setVisible(true);
maxChanceSpinner.setVisible(true);
tfPane.revalidate();
tfPane.repaint();
listener.valueChanged(chanceSpinner, chanceSpinner.getValue().toString() + "/" + maxChanceSpinner.getValue().toString());
}
}
});
chanceSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (entryTypeBox.getSelectedItem() == percent) {
listener.valueChanged(chanceSpinner, chanceSpinner.getValue().toString());
} else if (entryTypeBox.getSelectedItem() == ratio) {
listener.valueChanged(chanceSpinner, chanceSpinner.getValue().toString() + "/" + maxChanceSpinner.getValue().toString());
}
}
});
maxChanceSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
listener.valueChanged(chanceSpinner, chanceSpinner.getValue().toString() + "/" + maxChanceSpinner.getValue().toString());
}
});
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
chanceSpinner.setValue(1);
listener.valueChanged(chanceSpinner, null);
}
});
return chanceSpinner;
}
// public static JSpinner addDoubleField(JPanel pane, String label, Double initialValue, boolean editable) {
// return addDoubleField(pane, label, initialValue, editable, nullListener);
// }
@@ -644,8 +784,63 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return gdeBox;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public JComboBox<QuestStage> addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, @SuppressWarnings("rawtypes") 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<QuestStage> combo = new JComboBox<QuestStage>(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"})
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 +861,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 +939,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+"#"+((QuestStage)value).progress+":"+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 +970,64 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
}
public static class QuestStageComboModel extends AbstractListModel<QuestStage> implements ComboBoxModel<QuestStage> {
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);
}
@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> {
GameDataElement source;
@@ -892,7 +1161,5 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return null;
}
}

View File

@@ -0,0 +1,226 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
import com.jidesoft.swing.JideBoxLayout;
public class ExportProjectWizard extends JDialog {
private static final long serialVersionUID = -8745083621008868612L;
JPanel pane;
JLabel errorLabel, fileSelectionLabel;
JRadioButton asZip, overSources;
JComboBox<String> target;
JButton browse;
JButton okButton, cancelButton;
Project proj;
public ExportProjectWizard(Project proj) {
super(ATContentStudio.frame);
setTitle("Export project for inclusion in-game");
this.proj = proj;
pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
errorLabel = new JLabel();
pane.add(errorLabel, JideBoxLayout.FIX);
pane.add(new JLabel("Export this ATCS project..."), JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
asZip = new JRadioButton("... as a Zip archive");
radioGroup.add(asZip);
overSources = new JRadioButton("... into a game source folder");
radioGroup.add(overSources);
overSources.setSelected(true);
pane.add(asZip, JideBoxLayout.FIX);
pane.add(overSources, JideBoxLayout.FIX);
ActionListener updateListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateState();
}
};
asZip.addActionListener(updateListener);
overSources.addActionListener(updateListener);
target = new JComboBox<String>();
target.setEditable(true);
target.addActionListener(updateListener);
browse = new JButton("Browse");
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = new JFileChooser(){
private static final long serialVersionUID = -3001082967957619011L;
@Override
public boolean accept(File f) {
if (asZip.isSelected()) {
if (f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP")) {
return super.accept(f);
} else {
return false;
}
} else {
return f.isDirectory();
}
}
};
jfc.setFileSelectionMode(asZip.isSelected() ? JFileChooser.FILES_AND_DIRECTORIES : JFileChooser.DIRECTORIES_ONLY);
jfc.setSelectedFile(new File(target.getSelectedItem() == null ? "" : target.getSelectedItem().toString()));
jfc.setMultiSelectionEnabled(false);
int result = jfc.showOpenDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
File f = jfc.getSelectedFile();
if (asZip.isSelected() && !f.getAbsolutePath().substring(f.getAbsolutePath().length() - 4, f.getAbsolutePath().length()).equalsIgnoreCase(".zip")) {
f = new File(f.getAbsolutePath()+".zip");
}
target.setSelectedItem(f.getAbsolutePath());
updateState();
}
}
});
JPanel fileSelectionPane = new JPanel();
fileSelectionPane.setLayout(new JideBoxLayout(fileSelectionPane, JideBoxLayout.LINE_AXIS, 6));
fileSelectionLabel = new JLabel("Zip file: ");
fileSelectionPane.add(fileSelectionLabel, JideBoxLayout.FIX);
fileSelectionPane.add(target, JideBoxLayout.VARY);
fileSelectionPane.add(browse, JideBoxLayout.FIX);
pane.add(fileSelectionPane, JideBoxLayout.FIX);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
cancelButton = new JButton("Cancel");
buttonPane.add(cancelButton, JideBoxLayout.FIX);
okButton = new JButton("Ok");
buttonPane.add(okButton, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ExportProjectWizard.this.setVisible(false);
ExportProjectWizard.this.dispose();
}
});
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (asZip.isSelected()) {
ExportProjectWizard.this.proj.exportProjectAsZipPackage(new File(target.getSelectedItem().toString()));
} else {
ExportProjectWizard.this.proj.exportProjectOverGameSource(new File(target.getSelectedItem().toString()));
}
ExportProjectWizard.this.setVisible(false);
ExportProjectWizard.this.dispose();
}
});
updateState();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(500,150));
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
private void updateState() {
if (asZip.isSelected()) {
fileSelectionLabel.setText("Zip file: ");
} else {
fileSelectionLabel.setText("Game source folder: ");
}
File f = new File(target.getSelectedItem() == null ? "" : target.getSelectedItem().toString());
if (asZip.isSelected()) {
if (target.getSelectedItem() == null || target.getSelectedItem().toString().length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">You must select where to save the zip file.</font></html>");
okButton.setEnabled(false);
} else if (f.isDirectory()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected target is a directory. It should be a zip file.</font></html>");
okButton.setEnabled(false);
} else if (!(f.getName().toLowerCase().endsWith(".zip"))) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected target is not a zip file. It should be a zip file.</font></html>");
okButton.setEnabled(false);
} else if (f.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected target is an existing zip file. It will be overwritten.</font></html>");
okButton.setEnabled(true);
} else {
errorLabel.setText("<html><font color=\"#00AA00\">Everything looks good !</font></html>");
okButton.setEnabled(true);
}
} else {
if (target.getSelectedItem() == null || target.getSelectedItem().toString().length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">You must select an AT source root folder.</font></html>");
okButton.setEnabled(false);
} else if (!f.isDirectory() || !f.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source is not a folder. It should be an existing AT source root folder.</font></html>");
okButton.setEnabled(false);
} else {
File res = new File(f, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
File drawable = new File(f, SpriteSheetSet.DEFAULT_REL_PATH_IN_SOURCE);
File xml = new File(f, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!res.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"res\" folder.</font></html>");
okButton.setEnabled(true);
} else if (!drawable.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"drawable\" folder.</font></html>");
okButton.setEnabled(true);
} else if (!xml.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"xml\" folder.</font></html>");
okButton.setEnabled(true);
} else {
errorLabel.setText("<html><font color=\"#00AA00\">Everything looks good !</font></html>");
okButton.setEnabled(true);
}
}
}
revalidate();
repaint();
}
}

View File

@@ -338,6 +338,7 @@ public class JSONImportWizard extends JDialog {
} else if (existingNode.getDataType() == GameSource.Type.altered) {
errors.add("An item with id "+node.id+" is already altered in this project.");
} else {
node.jsonFile = existingNode.jsonFile;
warnings.add("An item with id "+node.id+" exists in the used game source. This one will be inserted as \"altered\"");
}
existingNode = null;
@@ -412,7 +413,7 @@ public class JSONImportWizard extends JDialog {
proj.createElements(created);
JSONElement lastNode = created.get(created.size() - 1);
if (lastNode != null) {
lastNode.save();
// lastNode.save();
ATContentStudio.frame.selectInTree(lastNode);
}
JSONImportWizard.this.setVisible(false);

View File

@@ -18,6 +18,7 @@ import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.NotificationListener;
@@ -54,7 +55,7 @@ public class NotificationsPane extends JList {
label.setBorder(BorderFactory.createLineBorder(Color.BLUE));
// label.setForeground(Color.WHITE);
}
f = f.deriveFont(10f);
f = f.deriveFont(10f*ATContentStudio.SCALING);
label.setFont(f);
return label;
}

View File

@@ -0,0 +1,35 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.Icon;
public class OverlayIcon implements Icon {
private Image background;
private Image overlay;
public OverlayIcon(Image background, Image overlay) {
this.background = background;
this.overlay = overlay;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawImage(background, x, y, null);
g.drawImage(overlay, x, y, null);
}
@Override
public int getIconWidth() {
return Math.max(background.getWidth(null), overlay.getWidth(null));
}
@Override
public int getIconHeight() {
return Math.max(background.getHeight(null), overlay.getHeight(null));
}
}

View File

@@ -33,6 +33,7 @@ import com.gpl.rpg.andorstrainer.AndorsTrainer;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.bookmarks.BookmarkEntry;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
@@ -140,14 +141,14 @@ public class ProjectsTree extends JPanel {
projectsTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
List<TreePath> newPaths = new ArrayList<TreePath>();
for (TreePath path : e.getPaths()) {
if (e.isAddedPath(path)) newPaths.add(path);
}
// List<TreePath> newPaths = new ArrayList<TreePath>();
// for (TreePath path : e.getPaths()) {
// if (e.isAddedPath(path)) newPaths.add(path);
// }
if (e.getPath() == null) {
ATContentStudio.frame.actions.selectionChanged(null, newPaths.toArray(new TreePath[newPaths.size()]));
ATContentStudio.frame.actions.selectionChanged(null, projectsTree.getSelectionPaths());
} else {
ATContentStudio.frame.actions.selectionChanged((ProjectTreeNode) e.getPath().getLastPathComponent(), newPaths.toArray(new TreePath[newPaths.size()]));
ATContentStudio.frame.actions.selectionChanged((ProjectTreeNode) e.getPath().getLastPathComponent(), projectsTree.getSelectionPaths());
}
}
});
@@ -242,17 +243,17 @@ public class ProjectsTree extends JPanel {
addNextSeparator = false;
}
if (actions.testWriter.isEnabled()) {
if (actions.createWriter.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.testWriter));
popupMenu.add(new JMenuItem(actions.createWriter));
}
// if (actions.testCommitWriter.isEnabled()) {
// addNextSeparator = true;
// popupMenu.add(new JMenuItem(actions.testCommitWriter));
// }
if (actions.createWriter.isEnabled()) {
if (actions.generateWriter.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createWriter));
popupMenu.add(new JMenuItem(actions.generateWriter));
}
if (addNextSeparator) {
popupMenu.add(new JSeparator());
@@ -595,6 +596,8 @@ public class ProjectsTree extends JPanel {
ATContentStudio.frame.openEditor((WorldmapSegment)node);
} else if (node instanceof WriterModeData) {
ATContentStudio.frame.openEditor((WriterModeData)node);
} else if (node instanceof BookmarkEntry) {
ATContentStudio.frame.openEditor(((BookmarkEntry)node).bookmarkedElement);
} else if (node instanceof SavedGame) {
if (konamiCodeEntered) {
ATContentStudio.frame.openEditor((SavedGame)node);

View File

@@ -40,7 +40,7 @@ public class StudioFrame extends JFrame {
private static final long serialVersionUID = -3391514100319186661L;
final ProjectsTree projectTree;
final EditorsArea editors;
@@ -165,6 +165,7 @@ public class StudioFrame extends JFrame {
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(i.getClassName());
ATContentStudio.scaleUIFont();
SwingUtilities.updateComponentTreeUI(ATContentStudio.frame);
ConfigCache.setFavoriteLaFClassName(i.getClassName());
} catch (ClassNotFoundException e1) {
@@ -212,6 +213,8 @@ public class StudioFrame extends JFrame {
openEditor((Spritesheet) node);
} else if (node instanceof TMXMap) {
openEditor((TMXMap) node);
} else if (node instanceof WorldmapSegment) {
openEditor((WorldmapSegment) node);
} else if (node instanceof WriterModeData) {
openEditor((WriterModeData) node);
}

View File

@@ -9,6 +9,7 @@ import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.jidesoft.swing.JideBoxLayout;
@@ -19,7 +20,7 @@ private static final long serialVersionUID = 8239669104275145995L;
super(parent, "Loading...");
this.setIconImage(DefaultIcons.getMainIconImage());
this.getContentPane().setLayout(new JideBoxLayout(this.getContentPane(), JideBoxLayout.PAGE_AXIS, 6));
this.getContentPane().add(new JLabel("<html><font size=5>Please wait.<br/>"+message+"</font></html>"), JideBoxLayout.VARY);
this.getContentPane().add(new JLabel("<html><font size="+(int)(5 * ATContentStudio.SCALING)+">Please wait.<br/>"+message+"</font></html>"), JideBoxLayout.VARY);
JMovingIdler idler = new JMovingIdler();
idler.setBackground(Color.WHITE);
idler.setForeground(Color.GREEN);
@@ -46,7 +47,7 @@ private static final long serialVersionUID = 8239669104275145995L;
info.setVisible(true);
workload.run();
info.dispose();
if (showConfirm) JOptionPane.showMessageDialog(parent, "<html><font size=5>Done !</font></html>");
if (showConfirm) JOptionPane.showMessageDialog(parent, "<html><font size="+(int)(5 * ATContentStudio.SCALING)+">Done !</font></html>");
};
}.start();
}

View File

@@ -31,8 +31,11 @@ import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
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.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.maps.Worldmap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGamesSet;
import com.gpl.rpg.atcontentstudio.model.tools.writermode.WriterModeData;
import com.gpl.rpg.atcontentstudio.model.tools.writermode.WriterModeDataSet;
@@ -56,6 +59,7 @@ public class WorkspaceActions {
public void actionPerformed(ActionEvent e) {
if (!(selectedNode instanceof Project)) return;
Workspace.closeProject((Project) selectedNode);
selectedNode = null;
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode instanceof Project);
@@ -122,19 +126,45 @@ public class WorkspaceActions {
ATContentStudio.frame.closeEditor(element);
element.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (element instanceof JSONElement) {
@SuppressWarnings("unchecked")
GameDataCategory<JSONElement> category = (GameDataCategory<JSONElement>) element.getParent();
category.remove(element);
if (impactedCategories.get(category) == null) {
impactedCategories.put(category, new HashSet<File>());
if (element.getParent() instanceof GameDataCategory<?>) {
@SuppressWarnings("unchecked")
GameDataCategory<JSONElement> category = (GameDataCategory<JSONElement>) element.getParent();
category.remove(element);
if (impactedCategories.get(category) == null) {
impactedCategories.put(category, new HashSet<File>());
}
GameDataElement newOne = element.getProject().getGameDataElement(((JSONElement)element).getClass(), element.id);
if (element instanceof Quest) {
for (QuestStage oldStage : ((Quest) element).stages) {
QuestStage newStage = newOne != null ? ((Quest) newOne).getStage(oldStage.progress) : null;
for (GameDataElement backlink : oldStage.getBacklinks()) {
backlink.elementChanged(oldStage, newStage);
}
}
}
for (GameDataElement backlink : element.getBacklinks()) {
backlink.elementChanged(element, newOne);
}
impactedCategories.get(category).add(((JSONElement) element).jsonFile);
}
impactedCategories.get(category).add(((JSONElement) element).jsonFile);
} else if (element instanceof TMXMap) {
TMXMapSet parent = (TMXMapSet) element.getParent();
parent.tmxMaps.remove(element);
((TMXMap)element).delete();
GameDataElement newOne = element.getProject().getMap(element.id);
for (GameDataElement backlink : element.getBacklinks()) {
backlink.elementChanged(element, newOne);
}
} else if (element instanceof WriterModeData) {
WriterModeDataSet parent = (WriterModeDataSet) element.getParent();
parent.writerModeDataList.remove(element);
} else if (element instanceof WorldmapSegment) {
if (element.getParent() instanceof Worldmap) {
((Worldmap)element.getParent()).remove(element);
element.save();
for (GameDataElement backlink : element.getBacklinks()) {
backlink.elementChanged(element, element.getProject().getWorldmapSegment(element.id));
}
}
}
}
new Thread() {
@@ -165,20 +195,52 @@ public class WorkspaceActions {
@Override
public void run() {
node.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (node.getParent() instanceof GameDataCategory<?>) {
((GameDataCategory<?>)node.getParent()).remove(node);
List<SaveEvent> events = node.attemptSave();
if (events == null || events.isEmpty()) {
node.save();
} else {
new SaveItemsWizard(events, null).setVisible(true);
if (node instanceof JSONElement) {
if (node.getParent() instanceof GameDataCategory<?>) {
((GameDataCategory<?>)node.getParent()).remove(node);
List<SaveEvent> events = node.attemptSave();
if (events == null || events.isEmpty()) {
node.save();
} else {
new SaveItemsWizard(events, null).setVisible(true);
}
GameDataElement newOne = node.getProject().getGameDataElement(((JSONElement)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, newOne);
}
}
// ((GameDataCategory<?>)node.getParent()).remove(node);
// List<SaveEvent> events = node.attemptSave();
// if (events == null || events.isEmpty()) {
// node.save();
// } else {
// new SaveItemsWizard(events, null).setVisible(true);
// }
} else if (node instanceof TMXMap) {
TMXMapSet parent = (TMXMapSet) node.getParent();
parent.tmxMaps.remove(node);
((TMXMap)node).delete();
GameDataElement newOne = node.getProject().getMap(node.id);
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, newOne);
}
} else if (node instanceof WriterModeData) {
WriterModeDataSet parent = (WriterModeDataSet) node.getParent();
parent.writerModeDataList.remove(node);
} else if (node instanceof WorldmapSegment) {
if (node.getParent() instanceof Worldmap) {
((Worldmap)node.getParent()).remove(node);
node.save();
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, node.getProject().getWorldmapSegment(node.id));
}
}
}
}
}.start();
@@ -192,12 +254,9 @@ public class WorkspaceActions {
for (TreePath selected : selectedPaths) {
if (selected.getLastPathComponent() instanceof GameDataElement && ((GameDataElement)selected.getLastPathComponent()).writable) {
elementsToDelete.add((GameDataElement) selected.getLastPathComponent());
multiMode = true;
} else {
multiMode = false;
break;
}
}
multiMode = elementsToDelete.size() > 1;
putValue(Action.NAME, "Delete all selected elements");
setEnabled(multiMode);
} else if (selectedNode instanceof GameDataElement && ((GameDataElement)selectedNode).writable) {
@@ -294,21 +353,7 @@ public class WorkspaceActions {
public ATCSAction exportProject = new ATCSAction("Export project", "Generates a zip file containing all the created & altered resources of the project, ready to merge with the game source."){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
JFileChooser chooser = new JFileChooser() {
private static final long serialVersionUID = 8039332384370636746L;
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP");
}
};
chooser.setMultiSelectionEnabled(false);
int result = chooser.showSaveDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
File f = chooser.getSelectedFile();
if (!f.getAbsolutePath().substring(f.getAbsolutePath().length() - 4, f.getAbsolutePath().length()).equalsIgnoreCase(".zip")) {
f = new File(f.getAbsolutePath()+".zip");
}
selectedNode.getProject().generateExportPackage(f);
}
new ExportProjectWizard(selectedNode.getProject()).setVisible(true);
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
@@ -340,7 +385,7 @@ public class WorkspaceActions {
};
};
public ATCSAction testWriter = new ATCSAction("Create dialogue sketch", "Create a dialogue sketch for fast dialogue edition"){
public ATCSAction createWriter = new ATCSAction("Create dialogue sketch", "Create a dialogue sketch for fast dialogue edition"){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
new WriterSketchCreationWizard(selectedNode.getProject()).setVisible(true);
@@ -375,7 +420,7 @@ public class WorkspaceActions {
}
};*/
public ATCSAction createWriter = new ATCSAction("Generate dialogue sketch", "Generates a dialogue sketch from this dialogue and its tree.") {
public ATCSAction generateWriter = new ATCSAction("Generate dialogue sketch", "Generates a dialogue sketch from this dialogue and its tree.") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null || !(selectedNode instanceof Dialogue)) return;
new WriterSketchCreationWizard(selectedNode.getProject(), (Dialogue)selectedNode).setVisible(true);
@@ -413,9 +458,9 @@ public class WorkspaceActions {
actions.add(exportProject);
actions.add(showAbout);
actions.add(exitATCS);
actions.add(testWriter);
// actions.add(testCommitWriter);
actions.add(createWriter);
// actions.add(testCommitWriter);
actions.add(generateWriter);
actions.add(editWorkspaceSettings);
selectionChanged(null, null);
}

View File

@@ -31,9 +31,10 @@ public class WorkspaceSettingsEditor extends JDialog {
JRadioButton useSystemDefaultImageViewerButton, useSystemDefaultImageEditorButton, useCustomImageEditorButton;
JTextField imageEditorCommandField;
JCheckBox useInternetBox;
JCheckBox translatorModeBox;
JComboBox<String> translatorLanguagesBox;
JCheckBox useInternetBox;
JCheckBox checkUpdatesBox;
@@ -53,7 +54,7 @@ public class WorkspaceSettingsEditor extends JDialog {
pane.add(getExternalToolsPane(), JideBoxLayout.FIX);
pane.add(getTranslatorModePane(), JideBoxLayout.FIX);
pane.add(getInternetPane(), JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
@@ -155,10 +156,14 @@ public class WorkspaceSettingsEditor extends JDialog {
return pane;
}
public JPanel getTranslatorModePane() {
CollapsiblePanel pane = new CollapsiblePanel("Translator options");
public JPanel getInternetPane() {
CollapsiblePanel pane = new CollapsiblePanel("Internet options");
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS));
useInternetBox = new JCheckBox("Allow connecting to internet to retrieve data from weblate and check for updates.");
pane.add(useInternetBox, JideBoxLayout.FIX);
translatorModeBox = new JCheckBox("Activate translator mode");
pane.add(translatorModeBox, JideBoxLayout.FIX);
@@ -171,14 +176,22 @@ public class WorkspaceSettingsEditor extends JDialog {
pane.add(new JLabel("If your language isn't here, complain on the forums at https://andorstrail.com/"), JideBoxLayout.FIX);
useInternetBox = new JCheckBox("Allow connecting to internet to retrieve data from weblate.");
pane.add(useInternetBox, JideBoxLayout.FIX);
checkUpdatesBox = new JCheckBox("Check for ATCS updates at startup");
pane.add(checkUpdatesBox, JideBoxLayout.FIX);
useInternetBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
translatorLanguagesBox.setEnabled(useInternetBox.isSelected() && translatorModeBox.isSelected());
translatorModeBox.setEnabled(useInternetBox.isSelected());
checkUpdatesBox.setEnabled(useInternetBox.isSelected());
}
});
translatorModeBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
translatorLanguagesBox.setEnabled(translatorModeBox.isSelected());
useInternetBox.setEnabled(translatorModeBox.isSelected());
}
});
@@ -196,19 +209,20 @@ public class WorkspaceSettingsEditor extends JDialog {
useSystemDefaultImageEditorButton.setSelected(settings.useSystemDefaultImageEditor.getCurrentValue());
useCustomImageEditorButton.setSelected(!(settings.useSystemDefaultImageViewer.getCurrentValue() || settings.useSystemDefaultImageEditor.getCurrentValue()));
imageEditorCommandField.setText(settings.imageEditorCommand.getCurrentValue());
//Translator
//Internet
useInternetBox.setSelected(settings.useInternet.getCurrentValue());
if (settings.translatorLanguage.getCurrentValue() != null) {
translatorModeBox.setSelected(true);
translatorLanguagesBox.setSelectedItem(settings.translatorLanguage.getCurrentValue());
translatorLanguagesBox.setEnabled(true);
useInternetBox.setEnabled(true);
translatorLanguagesBox.setEnabled(useInternetBox.isSelected());
} else {
translatorModeBox.setSelected(false);
translatorLanguagesBox.setSelectedItem(null);
translatorLanguagesBox.setEnabled(false);
useInternetBox.setEnabled(false);
}
useInternetBox.setSelected(settings.useInternet.getCurrentValue());
translatorModeBox.setEnabled(useInternetBox.isSelected());
checkUpdatesBox.setSelected(settings.checkUpdates.getCurrentValue());
checkUpdatesBox.setEnabled(useInternetBox.isSelected());
}
public void pushToModel() {
@@ -219,13 +233,14 @@ public class WorkspaceSettingsEditor extends JDialog {
settings.useSystemDefaultImageViewer.setCurrentValue(useSystemDefaultImageViewerButton.isSelected());
settings.useSystemDefaultImageEditor.setCurrentValue(useSystemDefaultImageEditorButton.isSelected());
settings.imageEditorCommand.setCurrentValue(imageEditorCommandField.getText());
//Translator
//Internet
settings.useInternet.setCurrentValue(useInternetBox.isSelected());
if (translatorModeBox.isSelected()) {
settings.translatorLanguage.setCurrentValue((String)translatorLanguagesBox.getSelectedItem());
} else {
settings.translatorLanguage.resetDefault();
}
settings.useInternet.setCurrentValue(useInternetBox.isSelected());
settings.checkUpdates.setCurrentValue(checkUpdatesBox.isSelected());
settings.save();
}

View File

@@ -35,13 +35,17 @@ public class ActorConditionEditor extends JSONElementEditor {
private IntegerBasedCheckBox positiveBox;
private IntegerBasedCheckBox stackingBox;
private JTextField roundVisualField;
//private JTextField roundVisualField;
@SuppressWarnings("rawtypes")
private JComboBox roundVisualField;
private JSpinner roundHpMinField;
private JSpinner roundHpMaxField;
private JSpinner roundApMinField;
private JSpinner roundApMaxField;
private JTextField fullRoundVisualField;
//private JTextField fullRoundVisualField;
@SuppressWarnings("rawtypes")
private JComboBox fullRoundVisualField;
private JSpinner fullRoundHpMinField;
private JSpinner fullRoundHpMaxField;
private JSpinner fullRoundApMinField;
@@ -82,7 +86,7 @@ public class ActorConditionEditor extends JSONElementEditor {
stackingBox = addIntegerBasedCheckBox(pane, "Stacking", ac.stacking, ac.writable, listener);
CollapsiblePanel roundEffectPane = new CollapsiblePanel("Effect every round (4s): ");
CollapsiblePanel roundEffectPane = new CollapsiblePanel("Effect every round (6s): ");
roundEffectPane.setLayout(new JideBoxLayout(roundEffectPane, JideBoxLayout.PAGE_AXIS));
final ActorCondition.RoundEffect roundEffect;
if (ac.round_effect != null) {
@@ -90,7 +94,7 @@ public class ActorConditionEditor extends JSONElementEditor {
} else {
roundEffect = new ActorCondition.RoundEffect();
}
roundVisualField = addTextField(roundEffectPane, "Visual effect ID: ", roundEffect.visual_effect, ac.writable, listener);
roundVisualField = addEnumValueBox(roundEffectPane, "Visual effect ID:", ActorCondition.VisualEffectID.values(), roundEffect.visual_effect, ac.writable, listener);//addTextField(roundEffectPane, "Visual effect ID: ", roundEffect.visual_effect, ac.writable, listener);
roundHpMinField = addIntegerField(roundEffectPane, "HP Bonus Min: ", roundEffect.hp_boost_min, true, ac.writable, listener);
roundHpMaxField = addIntegerField(roundEffectPane, "HP Bonus Max: ", roundEffect.hp_boost_max, true, ac.writable, listener);
roundApMinField = addIntegerField(roundEffectPane, "AP Bonus Min: ", roundEffect.ap_boost_min, true, ac.writable, listener);
@@ -99,7 +103,7 @@ public class ActorConditionEditor extends JSONElementEditor {
pane.add(roundEffectPane, JideBoxLayout.FIX);
CollapsiblePanel fullRoundEffectPane = new CollapsiblePanel("Effect every full round (20s): ");
CollapsiblePanel fullRoundEffectPane = new CollapsiblePanel("Effect every full round (25s): ");
fullRoundEffectPane.setLayout(new JideBoxLayout(fullRoundEffectPane, JideBoxLayout.PAGE_AXIS));
final ActorCondition.RoundEffect fullRoundEffect;
if (ac.full_round_effect != null) {
@@ -107,7 +111,7 @@ public class ActorConditionEditor extends JSONElementEditor {
} else {
fullRoundEffect = new ActorCondition.RoundEffect();
}
fullRoundVisualField = addTextField(fullRoundEffectPane, "Visual effect ID: ", fullRoundEffect.visual_effect, ac.writable, listener);
fullRoundVisualField = addEnumValueBox(fullRoundEffectPane, "Visual effect ID:", ActorCondition.VisualEffectID.values(), fullRoundEffect.visual_effect, ac.writable, listener);//addTextField(fullRoundEffectPane, "Visual effect ID: ", fullRoundEffect.visual_effect, ac.writable, listener);
fullRoundHpMinField = addIntegerField(fullRoundEffectPane, "HP Bonus min: ", fullRoundEffect.hp_boost_min, true, ac.writable, listener);
fullRoundHpMaxField = addIntegerField(fullRoundEffectPane, "HP Bonus max: ", fullRoundEffect.hp_boost_max, true, ac.writable, listener);
fullRoundApMinField = addIntegerField(fullRoundEffectPane, "AP Bonus min: ", fullRoundEffect.ap_boost_min, true, ac.writable, listener);
@@ -194,7 +198,7 @@ public class ActorConditionEditor extends JSONElementEditor {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.visual_effect = (String) value;
aCond.round_effect.visual_effect = (ActorCondition.VisualEffectID) value;
}
} else if (source == roundHpMinField) {
if (value == null) {
@@ -264,7 +268,7 @@ public class ActorConditionEditor extends JSONElementEditor {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.visual_effect = (String) value;
aCond.full_round_effect.visual_effect = (ActorCondition.VisualEffectID) value;
}
} else if (source == fullRoundHpMinField) {
if (value == null) {

View File

@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
@@ -22,6 +23,7 @@ import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
@@ -43,12 +45,14 @@ 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;
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.OverlayIcon;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.dialoguetree.DialogueGraphView;
import com.jidesoft.swing.JideBoxLayout;
@@ -92,9 +96,13 @@ public class DialogueEditor extends JSONElementEditor {
private JPanel rewardsParamsPane;
private MyComboBox rewardMap;
private JTextField rewardObjId;
@SuppressWarnings("rawtypes")
private JComboBox rewardObjIdCombo;
private MyComboBox rewardObj;
private JSpinner rewardValue;
private JComponent rewardValue;
private JRadioButton rewardConditionTimed;
private JRadioButton rewardConditionForever;
private JRadioButton rewardConditionClear;
private RepliesListModel repliesListModel;
@SuppressWarnings("rawtypes")
@@ -113,8 +121,10 @@ public class DialogueEditor extends JSONElementEditor {
private JComboBox requirementTypeCombo;
private JPanel requirementParamsPane;
private MyComboBox requirementObj;
private JTextField requirementObjId;
private JSpinner requirementValue;
@SuppressWarnings("rawtypes")
private JComboBox requirementSkill;
private JComponent requirementObjId;
private JComponent requirementValue;
private BooleanBasedCheckBox requirementNegated;
private DialogueGraphView dialogueGraphView;
@@ -356,6 +366,7 @@ public class DialogueEditor extends JSONElementEditor {
if (rewardObj != null) {
removeElementListener(rewardObj);
}
boolean immunity = false;
if (reward.type != null) {
switch (reward.type) {
case activateMapObjectGroup:
@@ -373,6 +384,13 @@ public class DialogueEditor extends JSONElementEditor {
rewardObj = null;
rewardValue = null;
break;
case mapchange:
rewardMap = addMapBox(pane, ((Dialogue)target).getProject(), "Map Name: ", reward.map, writable, listener);
rewardObjId = addTextField(pane, "Place: ", reward.reward_obj_id, writable, listener);
rewardObjIdCombo = null;
rewardObj = null;
rewardValue = null;
break;
case deactivateSpawnArea:
case removeSpawnArea:
case spawnAll:
@@ -382,14 +400,62 @@ public class DialogueEditor extends JSONElementEditor {
rewardObj = null;
rewardValue = null;
break;
case actorConditionImmunity:
immunity = true;
case actorCondition:
rewardMap = null;
rewardObjId = null;
rewardObjIdCombo = null;
rewardObj = addActorConditionBox(pane, ((Dialogue)target).getProject(), "Actor Condition: ", (ActorCondition) reward.reward_obj, writable, listener);
rewardValue = addIntegerField(pane, "Duration: ", reward.reward_value, false, writable, listener);
rewardConditionTimed = new JRadioButton("For a number of rounds");
pane.add(rewardConditionTimed, JideBoxLayout.FIX);
rewardValue = addIntegerField(pane, "Duration: ", reward.reward_value, 1, false, writable, listener);
rewardConditionForever = new JRadioButton("Forever");
pane.add(rewardConditionForever, JideBoxLayout.FIX);
if (!immunity) {
rewardConditionClear = new JRadioButton("Clear actor condition");
pane.add(rewardConditionClear, JideBoxLayout.FIX);
}
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(rewardConditionTimed);
radioGroup.add(rewardConditionForever);
if (!immunity) radioGroup.add(rewardConditionClear);
if (immunity) {
rewardConditionTimed.setSelected(reward.reward_value == null || (reward.reward_value != ActorCondition.DURATION_FOREVER && reward.reward_value != ActorCondition.MAGNITUDE_CLEAR));
rewardConditionForever.setSelected(reward.reward_value != null && reward.reward_value != ActorCondition.DURATION_FOREVER);
rewardConditionClear.setSelected(reward.reward_value != null && reward.reward_value != ActorCondition.MAGNITUDE_CLEAR);
} else {
rewardConditionTimed.setSelected(reward.reward_value != null && reward.reward_value != ActorCondition.DURATION_FOREVER);
rewardConditionForever.setSelected(reward.reward_value == null || reward.reward_value == ActorCondition.DURATION_FOREVER);
}
rewardValue.setEnabled(rewardConditionTimed.isSelected());
rewardConditionTimed.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(rewardConditionTimed, new Boolean(rewardConditionTimed.isSelected()));
}
});
rewardConditionForever.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(rewardConditionForever, new Boolean(rewardConditionForever.isSelected()));
}
});
if (!immunity) {
rewardConditionClear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(rewardConditionClear, new Boolean(rewardConditionClear.isSelected()));
}
});
}
break;
case alignmentChange:
case alignmentSet:
rewardMap = null;
rewardObjId = addTextField(pane, "Faction: ", reward.reward_obj_id, writable, listener);
rewardObjIdCombo = null;
@@ -414,19 +480,24 @@ public class DialogueEditor extends JSONElementEditor {
rewardMap = null;
rewardObjId = null;
rewardObj = addItemBox(pane, ((Dialogue)target).getProject(), "Item: ", (Item) reward.reward_obj, writable, listener);
rewardValue = addIntegerField(pane, "Quantity: ", reward.reward_value, false, writable, listener);
rewardValue = addIntegerField(pane, "Quantity: ", reward.reward_value, true, writable, listener);
break;
case removeQuestProgress:
case questProgress:
rewardMap = null;
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:
Requirement.SkillID skillId = null;
try {
skillId = reward.reward_obj_id == null ? null : Requirement.SkillID.valueOf(reward.reward_obj_id);
} catch(IllegalArgumentException e) {}
rewardMap = null;
rewardObjId = addTextField(pane, "Skill ID: ", reward.reward_obj_id, writable, listener);
rewardObjIdCombo = null;
rewardObjId = null;// addTextField(pane, "Skill ID: ", reward.reward_obj_id, writable, listener);
rewardObjIdCombo = addEnumValueBox(pane, "Skill ID: ", Requirement.SkillID.values(), skillId, writable, listener);
rewardObj = null;
rewardValue = null;
break;
@@ -613,10 +684,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);
}
@@ -633,7 +704,7 @@ public class DialogueEditor extends JSONElementEditor {
removeElementListener(requirementObj);
}
requirementTypeCombo = addEnumValueBox(pane, "Requirement type: ", Requirement.RequirementType.values(), requirement.type, writable, listener);
requirementTypeCombo = addEnumValueBox(pane, "Requirement type: ", Requirement.RequirementType.values(), requirement == null ? null : requirement.type, writable, listener);
requirementParamsPane = new JPanel();
requirementParamsPane.setLayout(new JideBoxLayout(requirementParamsPane, JideBoxLayout.PAGE_AXIS));
updateRequirementParamsEditorPane(requirementParamsPane, requirement, listener);
@@ -650,7 +721,7 @@ public class DialogueEditor extends JSONElementEditor {
removeElementListener(requirementObj);
}
if (requirement.type != null) {
if (requirement != null && requirement.type != null) {
switch (requirement.type) {
case consumedBonemeals:
case spentGold:
@@ -658,6 +729,11 @@ public class DialogueEditor extends JSONElementEditor {
requirementObjId = null;
requirementValue = addIntegerField(pane, "Quantity: ", requirement.required_value, false, writable, listener);
break;
case random:
requirementObj = null;
requirementObjId = addChanceField(pane, "Chance: ", requirement.required_obj_id, "50/100", writable, listener);
requirementValue = null;
break;
case hasActorCondition:
requirementObj = addActorConditionBox(pane, project, "Actor Condition: ", (ActorCondition) requirement.required_obj, writable, listener);
requirementObjId = null;
@@ -666,6 +742,8 @@ public class DialogueEditor extends JSONElementEditor {
case inventoryKeep:
case inventoryRemove:
case usedItem:
case wear:
case wearRemove:
requirementObj = addItemBox(pane, project, "Item: ", (Item) requirement.required_obj, writable, listener);
requirementObjId = null;
requirementValue = addIntegerField(pane, "Quantity: ", requirement.required_value, false, writable, listener);
@@ -679,11 +757,16 @@ 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:
Requirement.SkillID skillId = null;
try {
skillId = requirement.required_obj_id == null ? null : Requirement.SkillID.valueOf(requirement.required_obj_id);
} catch(IllegalArgumentException e) {}
requirementObj = null;
requirementObjId = addTextField(pane, "Skill ID:", requirement.required_obj_id, writable, listener);
requirementSkill = addEnumValueBox(pane, "Skill ID:", Requirement.SkillID.values(), skillId, writable, listener);
requirementObjId = null;//addTextField(pane, "Skill ID:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Level: ", requirement.required_value, false, writable, listener);
break;
case timerElapsed:
@@ -691,10 +774,35 @@ public class DialogueEditor extends JSONElementEditor {
requirementObjId = addTextField(pane, "Timer ID:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Timer value: ", requirement.required_value, false, writable, listener);
break;
case wear:
requirementObj = addItemBox(pane, project, "Item: ", (Item) requirement.required_obj, writable, listener);
requirementObjId = null;
requirementValue = null;
case factionScore:
requirementObj = null;
requirementObjId = addTextField(pane, "Faction ID:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Minimum score: ", requirement.required_value, true, writable, listener);
break;
case factionScoreEquals:
requirementObj = null;
requirementObjId = addTextField(pane, "Faction ID:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Exact value: ", requirement.required_value, true, writable, listener);
break;
case date:
requirementObj = null;
requirementObjId = addTextField(pane, "Date type YYYYMMTT:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Minimum date value: ", requirement.required_value, true, writable, listener);
break;
case dateEquals:
requirementObj = null;
requirementObjId = addTextField(pane, "Date type YYYYMMTT:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Exact date value: ", requirement.required_value, true, writable, listener);
break;
case time:
requirementObj = null;
requirementObjId = addTextField(pane, "Time type HHMMSS:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Minimum time value: ", requirement.required_value, true, writable, listener);
break;
case timeEquals:
requirementObj = null;
requirementObjId = addTextField(pane, "Time type HHMMSS:", requirement.required_obj_id, writable, listener);
requirementValue = addIntegerField(pane, "Exact time value: ", requirement.required_value, true, writable, listener);
break;
}
requirementNegated = addBooleanBasedCheckBox(pane, "Negate this requirement.", requirement.negated, writable, listener);
@@ -796,14 +904,31 @@ public class DialogueEditor extends JSONElementEditor {
label.setIcon(new ImageIcon(DefaultIcons.getObjectLayerIcon()));
break;
case actorCondition:
label.setText("Give actor condition "+rewardObjDesc+" for "+reward.reward_value+" turns");
boolean rewardClear = reward.reward_value != null && reward.reward_value.intValue() == ActorCondition.MAGNITUDE_CLEAR;
if (rewardClear) {
label.setText("Clear actor condition "+rewardObjDesc);
} else {
boolean rewardForever = reward.reward_value != null && reward.reward_value.intValue() == ActorCondition.DURATION_FOREVER;
label.setText("Give actor condition "+rewardObjDesc+(rewardForever ? " forever" : " for "+reward.reward_value+" turns"));
}
if (reward.reward_obj != null) label.setIcon(new ImageIcon(reward.reward_obj.getIcon()));
break;
case actorConditionImmunity:
boolean rewardForever = reward.reward_value == null || reward.reward_value.intValue() == ActorCondition.DURATION_FOREVER;
label.setText("Give immunity to actor condition "+rewardObjDesc+(rewardForever ? " forever" : " for "+reward.reward_value+" turns"));
if (reward.reward_obj != null) label.setIcon(new OverlayIcon(reward.reward_obj.getIcon(), DefaultIcons.getImmunityIcon()));
break;
case alignmentChange:
label.setText("Change alignment for faction "+rewardObjDesc+" : "+reward.reward_value);
label.setIcon(new ImageIcon(DefaultIcons.getAlignmentIcon()));
break;
case alignmentSet:
label.setText("Set alignment for faction "+rewardObjDesc+" : "+reward.reward_value);
label.setIcon(new ImageIcon(DefaultIcons.getAlignmentIcon()));
break;
case createTimer:
label.setText("Create timer "+rewardObjDesc);
label.setIcon(new ImageIcon(DefaultIcons.getTimerIcon()));
break;
case deactivateMapObjectGroup:
label.setText("Deactivate map object group "+rewardObjDesc+" on map "+reward.map_name);
@@ -825,12 +950,17 @@ public class DialogueEditor extends JSONElementEditor {
label.setText("Give quest progress "+rewardObjDesc+":"+reward.reward_value);
if (reward.reward_obj != null) label.setIcon(new ImageIcon(reward.reward_obj.getIcon()));
break;
case removeQuestProgress:
label.setText("Removes quest progress "+rewardObjDesc+":"+reward.reward_value);
if (reward.reward_obj != null) label.setIcon(new ImageIcon(reward.reward_obj.getIcon()));
break;
case removeSpawnArea:
label.setText("Remove all monsters in spawnarea area "+rewardObjDesc+" on map "+reward.map_name);
label.setIcon(new ImageIcon(DefaultIcons.getNPCIcon()));
break;
case skillIncrease:
label.setText("Increase skill "+rewardObjDesc+" level");
label.setIcon(new ImageIcon(DefaultIcons.getSkillIcon()));
break;
case spawnAll:
label.setText("Respawn all monsters in spawnarea area "+rewardObjDesc+" on map "+reward.map_name);
@@ -840,6 +970,10 @@ public class DialogueEditor extends JSONElementEditor {
label.setText("Change map filter to "+rewardObjDesc+" on map "+reward.map_name);
label.setIcon(new ImageIcon(DefaultIcons.getReplaceIcon()));
break;
case mapchange:
label.setText("Teleport to "+rewardObjDesc+" on map "+reward.map_name);
label.setIcon(new ImageIcon(DefaultIcons.getMapchangeIcon()));
break;
}
} else {
label.setText("New, undefined reward");
@@ -1065,7 +1199,21 @@ public class DialogueEditor extends JSONElementEditor {
if (req.required_obj.getIcon() != null) {
label.setIcon(new ImageIcon(req.required_obj.getIcon()));
}
} if (req.type == null) {
} else if (req.type == Requirement.RequirementType.skillLevel) {
label.setIcon(new ImageIcon(DefaultIcons.getSkillIcon()));
} else if (req.type == Requirement.RequirementType.spentGold) {
label.setIcon(new ImageIcon(DefaultIcons.getGoldIcon()));
} else if (req.type == Requirement.RequirementType.consumedBonemeals) {
label.setIcon(new ImageIcon(DefaultIcons.getBonemealIcon()));
} else if (req.type == Requirement.RequirementType.timerElapsed) {
label.setIcon(new ImageIcon(DefaultIcons.getTimerIcon()));
} else if (req.type == Requirement.RequirementType.factionScore || req.type == Requirement.RequirementType.factionScoreEquals) {
label.setIcon(new ImageIcon(DefaultIcons.getAlignmentIcon()));
} else if (req.type == Requirement.RequirementType.date || req.type == Requirement.RequirementType.dateEquals ||
req.type == Requirement.RequirementType.time || req.type == Requirement.RequirementType.timeEquals) {
label.setIcon(new ImageIcon(DefaultIcons.getDateIcon()));
}
if (req.type == null) {
label.setText("New, undefined requirement.");
}
}
@@ -1149,7 +1297,33 @@ 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 == rewardConditionClear) {
selectedReward.reward_value = ActorCondition.MAGNITUDE_CLEAR;
rewardValue.setEnabled(false);
rewardsListModel.itemChanged(selectedReward);
} else if (source == rewardConditionForever) {
selectedReward.reward_value = ActorCondition.DURATION_FOREVER;
rewardValue.setEnabled(false);
rewardsListModel.itemChanged(selectedReward);
} else if (source == rewardConditionTimed) {
selectedReward.reward_value = (Integer) ((JSpinner)rewardValue).getValue();
rewardValue.setEnabled(true);
rewardsListModel.itemChanged(selectedReward);
} else if (source == replyTypeCombo) {
updateRepliesParamsEditorPane(repliesParamsPane, selectedReply, this);
@@ -1185,12 +1359,35 @@ public class DialogueEditor extends JSONElementEditor {
selectedRequirement.required_obj_id = null;
}
requirementsListModel.itemChanged(selectedRequirement);
} else if (source == requirementSkill) {
if (selectedRequirement.required_obj != null) {
selectedRequirement.required_obj.removeBacklink(dialogue);
selectedRequirement.required_obj = null;
}
if (selectedRequirement.type == Requirement.RequirementType.skillLevel) {
selectedRequirement.required_obj_id = value == null ? null : value.toString();
}
requirementsListModel.itemChanged(selectedRequirement);
} else if (source == requirementObjId) {
selectedRequirement.required_obj_id = (String) value;
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;

View File

@@ -50,7 +50,7 @@ public class DroplistEditor extends JSONElementEditor {
private DroppedItemsListModel droppedItemsListModel;
private JSpinner qtyMinField;
private JSpinner qtyMaxField;
private JSpinner chanceField;
private JComponent chanceField;
public DroplistEditor(Droplist droplist) {
super(droplist, droplist.getDesc(), droplist.getIcon());
@@ -142,7 +142,7 @@ public class DroplistEditor extends JSONElementEditor {
itemCombo = addItemBox(pane, proj, "Item: ", di.item, writable, listener);
qtyMinField = addIntegerField(pane, "Quantity min: ", di.quantity_min, false, writable, listener);
qtyMaxField = addIntegerField(pane, "Quantity max: ", di.quantity_max, false, writable, listener);
chanceField = addDoubleField(pane, "Chance: ", di.chance, writable, listener);
chanceField = addChanceField(pane, "Chance: ", di.chance, "100", writable, listener);//addDoubleField(pane, "Chance: ", di.chance, writable, listener);
}
pane.revalidate();
pane.repaint();
@@ -221,9 +221,9 @@ public class DroplistEditor extends JSONElementEditor {
Droplist.DroppedItem di = (Droplist.DroppedItem)value;
if (di.item != null) {
label.setIcon(new ImageIcon(di.item.getIcon()));
label.setText(di.chance+"% to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item.getDesc());
label.setText(di.chance+(di.chance != null && di.chance.contains("/") ? "" : "%")+" to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item.getDesc());
} else if (!isNull(di)) {
label.setText(di.chance+"% to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item_id);
label.setText(di.chance+(di.chance != null && di.chance.contains("/") ? "" : "%")+" to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item_id);
} else {
label.setText("New, undefined, dropped item.");
}
@@ -283,7 +283,7 @@ public class DroplistEditor extends JSONElementEditor {
selectedItem.quantity_max = (Integer) value;
droppedItemsListModel.itemChanged(selectedItem);
} else if (source == chanceField) {
selectedItem.chance = (Double) value;
selectedItem.chance = (String) value;
droppedItemsListModel.itemChanged(selectedItem);
}

View File

@@ -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,6 +40,8 @@ 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.JideTabbedPane;
@@ -65,7 +70,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);
@@ -85,6 +94,7 @@ public abstract class JSONElementEditor extends Editor {
jsonEditorPane.setText(((JSONElement)target).toJsonString());
jsonEditorPane.setEditable(((JSONElement)target).writable);
jsonEditorPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
jsonEditorPane.setFont(jsonEditorPane.getFont().deriveFont(ATContentStudio.SCALING * jsonEditorPane.getFont().getSize()));
JPanel result = new JPanel();
result.setLayout(new BorderLayout());
result.add(jsonEditorPane, BorderLayout.CENTER);
@@ -178,13 +188,23 @@ 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);
}
}
}
});
savePane.add(delete, JideBoxLayout.FIX);
} else {
if (proj.alteredContent.gameData.getGameDataElement(concreteNodeClass, node.id) != null) {
savePane.add(message = new JLabel(ALTERED_EXISTS_MESSAGE), JideBoxLayout.FIX);
@@ -223,8 +243,10 @@ public abstract class JSONElementEditor extends Editor {
}
JButton prev = new JButton(new ImageIcon(DefaultIcons.getArrowLeftIcon()));
JButton next = new JButton(new ImageIcon(DefaultIcons.getArrowRightIcon()));
final JButton bookmark = new JButton(new ImageIcon(node.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon()));
savePane.add(prev, JideBoxLayout.FIX);
savePane.add(next, JideBoxLayout.FIX);
savePane.add(bookmark, JideBoxLayout.FIX);
if (node.getParent().getIndex(node) == 0) {
prev.setEnabled(false);
}
@@ -249,6 +271,20 @@ public abstract class JSONElementEditor extends Editor {
}
}
});
bookmark.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (node.bookmark == null) {
node.getProject().bookmark(node);
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon()));
} else {
node.bookmark.delete();
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon()));
}
}
});
//Placeholder. Fills the eventual remaining space.
savePane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(savePane, JideBoxLayout.FIX);
@@ -283,6 +319,7 @@ public abstract class JSONElementEditor extends Editor {
}
@SuppressWarnings("unchecked")
public boolean idChanging() {
JSONElement node = (JSONElement) target;
List<GameDataElement> toModify = new LinkedList<GameDataElement>();

View File

@@ -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;
@@ -38,20 +40,23 @@ public class QuestEditor extends JSONElementEditor {
private static final long serialVersionUID = 5701667955210615366L;
private static final Integer one = 1;
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<QuestStage> stagesList;
// private JPanel stagesParamPane;
private JSpinner progressField;
private JTextArea logTextField;
private JSpinner xpRewardField;
private IntegerBasedCheckBox finishQuestBox;
public QuestEditor(Quest quest) {
@@ -72,242 +77,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<QuestStage>(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<QuestStage> {
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<QuestStage>();
}
}
@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.QuestStage>();
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<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
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<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@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 +314,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 +340,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;
}
}
}

View File

@@ -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;
@@ -48,11 +49,14 @@ import prefuse.visual.expression.InGroupPredicate;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor;
import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration;
import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration.WeblateTranslationUnit;
import com.jidesoft.swing.JideBoxLayout;
public class DialogueGraphView extends Display {
@@ -68,13 +72,19 @@ 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 String TRANSLATION_LOADING="Loading translation...";
private String translationHeader="\n---[ Translation from weblate ]---\n";
private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema();
private Dialogue dialogue;
private Image npcIcon;
private Graph graph;
private Boolean translatorMode;
private Map<Dialogue, Node> cells = new HashMap<Dialogue, Node>();
@@ -86,6 +96,10 @@ public class DialogueGraphView extends Display {
} else {
npcIcon = DefaultIcons.getNPCIcon();
}
translatorMode = Workspace.activeWorkspace.settings.useInternet.getCurrentValue() && Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null;
if (translatorMode) {
translationHeader = "\n---[ Translation in "+Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue()+" ]---\n";
}
loadGraph();
// add visual data groups
@@ -146,7 +160,7 @@ public class DialogueGraphView extends Display {
// now create the main layout routine
ActionList layout = new ActionList();//Activity.INFINITY);
NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, 40, 40);
NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, translatorMode ? 80 : 40, translatorMode ? 80 : 40);
treeLayout.setLayoutAnchor(new Point2D.Double(25,300));
layout.add(treeLayout);
layout.add(new EdgesLabelDecoratorLayout(EDGES_LABELS));
@@ -174,6 +188,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);
}
@@ -183,9 +198,26 @@ public class DialogueGraphView extends Display {
if (dialogue.switch_to_npc != null) {
npcIcon = dialogue.switch_to_npc.getIcon();
}
Node dNode = graph.addNode();
final Node dNode = graph.addNode();
cells.put(dialogue, dNode);
dNode.setString(LABEL, dialogue.message != null ? dialogue.message : "[Selector]");
String label;
Thread t = null;
if (dialogue.message == null) {
label = "[Selector]";
} else if (translatorMode) {
label = dialogue.message+translationHeader+TRANSLATION_LOADING;
final String message = dialogue.message;
t = new Thread("Get weblate translation for "+message) {
public void run() {
WeblateTranslationUnit unit = WeblateIntegration.getTranslationUnit(message);
dNode.setString(LABEL, message+translationHeader+unit.translatedText);
};
};
} else {
label = dialogue.message;
}
dNode.setString(LABEL, label);
if (t != null) t.start();
dNode.set(ICON, npcIcon);
dNode.set(TARGET, dialogue);
if (dialogue.replies != null) {
@@ -203,11 +235,27 @@ public class DialogueGraphView extends Display {
}
public Node addReply(Dialogue d, Dialogue.Reply r, Image npcIcon) {
Node rNode;
final Node rNode;
if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) {
//Normal reply...
rNode = graph.addNode();
rNode.setString(LABEL, r.text);
// rNode.setString(LABEL, translatorMode ? r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText : r.text);
String label;
Thread t = null;
if (translatorMode) {
label = r.text+translationHeader+TRANSLATION_LOADING;
final String message = r.text;
t = new Thread("Get weblate translation for "+message) {
public void run() {
WeblateTranslationUnit unit = WeblateIntegration.getTranslationUnit(message);
rNode.setString(LABEL, message+translationHeader+unit.translatedText);
};
};
} else {
label = r.text;
}
rNode.setString(LABEL, label);
if (t != null) t.start();
rNode.set(ICON, DefaultIcons.getHeroIcon());
rNode.set(TARGET, d);
rNode.set(REPLY, r);
@@ -224,6 +272,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 +549,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);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,10 +7,14 @@ import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
@@ -19,15 +23,21 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.JComponent;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.Scrollable;
import javax.swing.ToolTipManager;
import tiled.view.MapRenderer;
import tiled.view.OrthogonalRenderer;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.maps.MapChange;
import com.gpl.rpg.atcontentstudio.model.maps.MapObject;
import com.gpl.rpg.atcontentstudio.model.maps.MapObjectGroup;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
@@ -46,27 +56,141 @@ public class WorldMapView extends JComponent implements Scrollable {
public Map<String, Rectangle> mapLocations = new LinkedHashMap<String, Rectangle>();
public ListSelectionModel selectedSelectionModel = null;
public ListModel<TMXMap> selectedListModel = null;
public Set<String> selected = new HashSet<String>();
public ListModel<TMXMap> highlightedListModel = null;
public float zoomLevel = 0.1f;
int sizeX = 0, sizeY = 0;
int offsetX = 0, offsetY = 0;
static final Color selectOutlineColor = new Color(255, 0, 0);
static final Stroke selectOutlineStroke = new BasicStroke(4f);
static final Color highlightOutlineColor = Color.CYAN;
static final Stroke highlightOutlineStroke = new BasicStroke(4f);
static final Color mapIdLabelOutlineColor = Color.BLACK;
static final Stroke thinLabelOutlineStroke = new BasicStroke(1.5f);
static final Stroke labelOutlineStroke = new BasicStroke(3f);
public WorldMapView(WorldmapSegment worldmap) {
this.worldmap = worldmap;
this.proj = worldmap.getProject();
updateFromModel();
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
String selectedMap = null;
// boolean update = false;
int x = (int) (e.getX() / zoomLevel);
int y = (int) (e.getY() / zoomLevel);
for (String s : mapLocations.keySet()) {
if (mapLocations.get(s).contains(x, y)) {
selectedMap = s;
break;
}
}
if (selectedMap != null) {
x = x - mapLocations.get(selectedMap).x;
y = y - mapLocations.get(selectedMap).y;
//Look for a mapchange there
TMXMap map = proj.getMap(selectedMap);
boolean mapchangeFound = false;
for (MapObjectGroup group : map.groups) {
for (MapObject obj : group.mapObjects) {
if (obj instanceof MapChange) {
if (x >= obj.x && x < obj.x + obj.w && y >= obj.y && y < obj.y + obj.h) {
String mapId = ((MapChange)obj).map != null ? ((MapChange)obj).map.id : ((MapChange)obj).map_id;
mapChangeClicked(e, proj.getMap(selectedMap), proj.getMap(mapId));
mapchangeFound = true;
}
}
}
}
if (!mapchangeFound) {
mapClicked(e, WorldMapView.this.worldmap.getProject().getMap(selectedMap));
}
} else {
backgroundClicked(e);
}
}
});
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
String selectedMap = null;
int x = (int) (e.getX() / zoomLevel);
int y = (int) (e.getY() / zoomLevel);
for (String s : mapLocations.keySet()) {
if (mapLocations.get(s).contains(x, y)) {
selectedMap = s;
break;
}
}
if (selectedMap != null) {
//Reuse x,y to indicate to tile-within-the-map coordinates.
x = x - mapLocations.get(selectedMap).x;
y = y - mapLocations.get(selectedMap).y;
//Look for a mapchange there
TMXMap map = proj.getMap(selectedMap);
boolean mapchangeFound = false;
for (MapObjectGroup group : map.groups) {
for (MapObject obj : group.mapObjects) {
if (obj instanceof MapChange) {
if (x >= obj.x && x < obj.x + obj.w && y >= obj.y && y < obj.y + obj.h) {
String mapId = ((MapChange)obj).map != null ? ((MapChange)obj).map.id : ((MapChange)obj).map_id;
setToolTipText(selectedMap+"->"+mapId);
mapchangeFound = true;
}
}
}
}
if (!mapchangeFound) {
setToolTipText(selectedMap);
}
ToolTipManager.sharedInstance().registerComponent(WorldMapView.this);
ToolTipManager.sharedInstance().setEnabled(true);
} else {
ToolTipManager.sharedInstance().setEnabled(false);
ToolTipManager.sharedInstance().unregisterComponent(WorldMapView.this);
setToolTipText(null);
}
}
});
}
@Override
public Point getToolTipLocation(MouseEvent event) {
return event.getPoint();
}
private void paintOnGraphics(Graphics2D g2) {
g2.setPaint(new Color(100, 100, 100));
g2.fillRect(0, 0, sizeX, sizeY);
g2.setPaint(new Color(255, 0, 0));
g2.setStroke(new BasicStroke(4));
g2.setPaint(selectOutlineColor);
g2.setStroke(selectOutlineStroke);
Font areaNameFont = g2.getFont();
areaNameFont = areaNameFont.deriveFont(70f).deriveFont(Font.BOLD);
Font mapIdFont = g2.getFont();
mapIdFont = mapIdFont.deriveFont(50f).deriveFont(Font.BOLD);
for (String s : mapLocations.keySet()) {
g2.setFont(mapIdFont);
FontMetrics mifm = g2.getFontMetrics();
int mapIdLabelHeight = mifm.getHeight();
for (String s : new HashSet<String>(mapLocations.keySet())) {
int x = mapLocations.get(s).x;
int y = mapLocations.get(s).y;
@@ -83,8 +207,8 @@ public class WorldMapView extends JComponent implements Scrollable {
if (layer instanceof tiled.core.TileLayer && layer.isVisible()) {
if (layer.getName().equalsIgnoreCase("walkable")) continue;
renderer.paintTileLayer(g2, (tiled.core.TileLayer) layer);
} else if (layer instanceof tiled.core.ObjectGroup && layer.isVisible()) {
// paintObjectGroup(g2, map, (tiled.core.ObjectGroup) layer);
} else if (layer instanceof tiled.core.ObjectGroup) {
paintObjectGroup(g2, map, (tiled.core.ObjectGroup) layer);
}
}
if (map.colorFilter != null) {
@@ -93,39 +217,119 @@ public class WorldMapView extends JComponent implements Scrollable {
MapColorFilters.applyColorfilter(map.colorFilter, g2);
g2.setClip(oldClip);
}
if (selected.contains(s)) {
g2.drawRect(0, 0, map.tmxMap.getWidth() * TILE_SIZE, map.tmxMap.getHeight() * TILE_SIZE);
}
g2.translate(-x, -y);
}
if (highlightedListModel != null) {
outlineFromListModel(g2, highlightedListModel, null, highlightOutlineColor, highlightOutlineStroke, mapIdFont, mapIdLabelHeight);
}
Font f = g2.getFont();
f = f.deriveFont(70f).deriveFont(Font.BOLD);
g2.setFont(f);
g2.setStroke(new BasicStroke(3));
if (selectedListModel != null && selectedSelectionModel != null) {
outlineFromListModel(g2, selectedListModel, selectedSelectionModel, selectOutlineColor, selectOutlineStroke, mapIdFont, mapIdLabelHeight);
}
g2.setStroke(labelOutlineStroke);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(areaNameFont);
FontMetrics fm = g2.getFontMetrics();
FontRenderContext frc = g2.getFontRenderContext();
for (String s : worldmap.labels.keySet()) {
String label = worldmap.labels.get(s).name;
Rectangle areaCovered = new Rectangle(0, 0, -1, -1);
for (String map : worldmap.labelledMaps.get(s)) {
areaCovered.add(mapLocations.get(map));
if (label != null) {
Rectangle areaCovered = new Rectangle(0, 0, -1, -1);
for (String map : worldmap.labelledMaps.get(s)) {
areaCovered.add(mapLocations.get(map));
}
Rectangle2D stringBounds = fm.getStringBounds(label, g2);
GlyphVector gv = areaNameFont.createGlyphVector(frc, label);
g2.setColor(Color.WHITE);
g2.fill(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
g2.setColor(Color.BLACK);
g2.draw(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
}
Rectangle2D stringBounds = fm.getStringBounds(label, g2);
GlyphVector gv = f.createGlyphVector(frc, label);
g2.setColor(Color.WHITE);
g2.fill(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
g2.setColor(Color.BLACK);
g2.draw(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
}
}
private void paintObjectGroup(Graphics2D g2d, TMXMap map, tiled.core.ObjectGroup layer) {
for (MapObjectGroup group : map.groups) {
if (group.tmxGroup == layer) {
for (MapObject object : group.mapObjects) {
if (object instanceof MapChange) {
// Only show mapchange areas pointing to maps not shown in this worldmap
if (((MapChange)object).map != null && !mapLocations.containsKey(((MapChange)object).map.id)) {
drawObject(object, g2d, new Color(20, 20, 190));
}
}
}
break;
}
}
}
private void drawObject(MapObject object, Graphics2D g2d, Color color) {
g2d.setPaint(color);
g2d.drawRect(object.x+1, object.y+1, object.w-3, object.h-3);
g2d.drawRect(object.x+2, object.y+2, object.w-5, object.h-5);
g2d.setPaint(color.darker().darker());
g2d.drawLine(object.x, object.y + object.h - 1, object.x + object.w - 1, object.y + object.h - 1);
g2d.drawLine(object.x + object.w - 1, object.y, object.x + object.w - 1, object.y + object.h - 1);
g2d.drawLine(object.x + 3, object.y + 3, object.x + object.w - 4, object.y + 3);
g2d.drawLine(object.x + 3, object.y + 3, object.x + 3, object.y + object.h - 4);
g2d.setPaint(color.brighter().brighter().brighter());
g2d.drawLine(object.x, object.y, object.x + object.w - 1, object.y);
g2d.drawLine(object.x, object.y, object.x, object.y + object.h - 1);
g2d.drawLine(object.x + 3, object.y + object.h - 4, object.x + object.w - 4, object.y + object.h - 4);
g2d.drawLine(object.x + object.w - 4, object.y + 3, object.x + object.w - 4, object.y + object.h - 4);
Image img = object.getIcon();
g2d.setColor(new Color(255, 255, 255, 120));
g2d.fillRect(object.x + 2, object.y + 2, img.getWidth(null), img.getHeight(null));
g2d.drawImage(object.getIcon(), object.x + 2, object.y + 2, null);
}
private void outlineFromListModel(Graphics2D g2, ListModel<TMXMap> listModel, ListSelectionModel selectionModel, Color outlineColor, Stroke outlineStroke, Font mapIdFont, int mapIdLabelHeight) {
for (int i =0; i<listModel.getSize(); i++) {
//No selection model ? We want to highlight the whole list.
if (selectionModel == null || selectionModel.isSelectedIndex(i)) {
TMXMap map = listModel.getElementAt(i);
int x = mapLocations.get(map.id).x;
int y = mapLocations.get(map.id).y;
g2.translate(x, y);
GlyphVector gv = mapIdFont.createGlyphVector(g2.getFontRenderContext(), map.id);
g2.setStroke(outlineStroke);
g2.setColor(outlineColor);
g2.drawRect(0, 0, map.tmxMap.getWidth() * TILE_SIZE, map.tmxMap.getHeight() * TILE_SIZE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(thinLabelOutlineStroke);
g2.fill(gv.getOutline(8, 8 + mapIdLabelHeight));
g2.setColor(mapIdLabelOutlineColor);
g2.draw(gv.getOutline(8, 8 + mapIdLabelHeight));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2.translate(-x, -y);
}
}
}
public List<String> getSelectedMapsIDs() {
List<String> result = new ArrayList<String>();
for (int i =0; i<selectedListModel.getSize(); i++) {
if (selectedSelectionModel.isSelectedIndex(i)) {
TMXMap map = selectedListModel.getElementAt(i);
result.add(map.id);
}
}
return result;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
@@ -140,6 +344,35 @@ public class WorldMapView extends JComponent implements Scrollable {
}
public interface MapClickListener {
public void mapClicked(MouseEvent e, TMXMap m);
public void mapChangeClicked(MouseEvent e, TMXMap m, TMXMap changeTarget);
public void backgroundClicked(MouseEvent e);
}
private List<MapClickListener> listeners = new CopyOnWriteArrayList<MapClickListener>();
public void addMapClickListener(MapClickListener l) {
listeners.add(l);
}
public void removeMapClickListener(MapClickListener l) {
listeners.remove(l);
}
private void mapClicked(MouseEvent e, TMXMap m) {
for (MapClickListener l : listeners) l.mapClicked(e, m);
}
private void mapChangeClicked(MouseEvent e, TMXMap m, TMXMap changeTarget) {
for (MapClickListener l : listeners) l.mapChangeClicked(e, m, changeTarget);
}
private void backgroundClicked(MouseEvent e) {
for (MapClickListener l : listeners) l.backgroundClicked(e);
}
// private boolean paintObjectGroup(Graphics2D g2d, TMXMap map, tiled.core.ObjectGroup layer) {
// boolean paintSelected = false;
// for (MapObjectGroup group : map.groups) {
@@ -247,6 +480,10 @@ public class WorldMapView extends JComponent implements Scrollable {
offsetX = worldmap.segmentX * TILE_SIZE;
offsetY = worldmap.segmentY * TILE_SIZE;
for (String s : worldmap.mapLocations.keySet()) {
if (proj.getMap(s) == null) {
System.err.println("Warning. Worldmap "+worldmap.id+" references map "+s+" but it doesn't exist in this project");
continue;
}
int x = worldmap.mapLocations.get(s).x * TILE_SIZE;
int w = proj.getMap(s).tmxMap.getWidth() * TILE_SIZE;
int y = worldmap.mapLocations.get(s).y * TILE_SIZE;
@@ -262,6 +499,13 @@ public class WorldMapView extends JComponent implements Scrollable {
public void pushToModel() {
worldmap.segmentX = offsetX / TILE_SIZE;
worldmap.segmentY = offsetY / TILE_SIZE;
for (String id : worldmap.mapLocations.keySet()) {
if (worldmap.getProject().getMap(id) == null) {
System.err.println("Warning. Worldmap "+worldmap.id+" references map "+id+" but it doesn't exist in this project");
continue;
}
worldmap.getProject().getMap(id).removeBacklink(worldmap);
}
worldmap.mapLocations.clear();
for (String s : mapLocations.keySet()) {
int x = mapLocations.get(s).x / TILE_SIZE;
@@ -270,14 +514,12 @@ public class WorldMapView extends JComponent implements Scrollable {
worldmap.mapLocations.put(s, new Point(x, y));
}
List<String> toRemove = new ArrayList<String>();
for (String s : worldmap.labels.keySet()) {
if (!mapLocations.containsKey(s)) {
toRemove.add(s);
for (String id : worldmap.mapLocations.keySet()) {
if (worldmap.getProject().getMap(id) == null) {
System.err.println("Warning. Worldmap "+worldmap.id+" references map "+id+" but it doesn't exist in this project");
continue;
}
}
for (String s : toRemove) {
worldmap.labels.remove(s);
worldmap.getProject().getMap(id).addBacklink(worldmap);
}
}

View File

@@ -1,43 +1,34 @@
package com.gpl.rpg.atcontentstudio.ui.sprites;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.ScrollPaneConstants;
import javax.swing.*;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet.Category;
import com.gpl.rpg.atcontentstudio.utils.SpriteUtils;
public class SpriteChooser extends JDialog {
private static final long serialVersionUID = -6018113265015159521L;
private static final int STD_WIDTH = 32;
private static final int STD_HEIGHT = 32;
private static final int MAX_PER_ROW = 10;
public static Map<Project, Map<Spritesheet.Category, SpriteChooser>> cache = new LinkedHashMap<Project, Map<Spritesheet.Category,SpriteChooser>>();
public static Map<Project, Map<Spritesheet.Category, List<Spritesheet>>> cacheValidator = new LinkedHashMap<Project, Map<Category,List<Spritesheet>>>();
public static Map<Project, Map<Spritesheet.Category, SpriteChooser>> cache = new LinkedHashMap<Project, Map<Spritesheet.Category, SpriteChooser>>();
public static Map<Project, Map<Spritesheet.Category, List<Spritesheet>>> cacheValidator = new LinkedHashMap<Project, Map<Category, List<Spritesheet>>>();
public static SpriteChooser getChooser(Project proj, Spritesheet.Category category) {
if (cache.get(proj) == null) {
cache.put(proj, new LinkedHashMap<Spritesheet.Category, SpriteChooser>());
@@ -46,13 +37,13 @@ public class SpriteChooser extends JDialog {
cache.get(proj).put(category, new SpriteChooser(proj, category));
} else {
List<Spritesheet> spritesheets = new ArrayList<Spritesheet>();
for (int i=0; i<proj.getSpritesheetCount(); i++) {
for (int i = 0; i < proj.getSpritesheetCount(); i++) {
Spritesheet sheet = proj.getSpritesheet(i);
if (sheet.category == category) {
spritesheets.add(sheet);
}
}
if ( !spritesheets.equals(cacheValidator.get(proj).get(category)) ) {
if (!spritesheets.equals(cacheValidator.get(proj).get(category))) {
cache.get(proj).put(category, new SpriteChooser(proj, category));
}
}
@@ -65,20 +56,20 @@ public class SpriteChooser extends JDialog {
wanted.pack();
return wanted;
}
private ButtonGroup group;
// private IconButton selectedOne = null;
// private JButton ok;
// private JButton cancel;
public String selectedIconId = null;
public SpriteChooser(Project proj, Category category) {
super(ATContentStudio.frame);
setTitle("Select a sprite");
setModalityType(ModalityType.APPLICATION_MODAL);
List<Spritesheet> spritesheets = new ArrayList<Spritesheet>();
for (int i=0; i<proj.getSpritesheetCount(); i++) {
for (int i = 0; i < proj.getSpritesheetCount(); i++) {
Spritesheet sheet = proj.getSpritesheet(i);
if (sheet.category == category) {
spritesheets.add(sheet);
@@ -88,8 +79,8 @@ public class SpriteChooser extends JDialog {
cacheValidator.put(proj, new LinkedHashMap<Spritesheet.Category, List<Spritesheet>>());
}
cacheValidator.get(proj).put(category, spritesheets);
JPanel pane = new JPanel();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
@@ -101,16 +92,20 @@ public class SpriteChooser extends JDialog {
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
List<Point> reservedSlots = new ArrayList<Point>();
Point nextFreeSlot = new Point(0, 0);
int i;
Image img;
BufferedImage img;
group = new ButtonGroup();
//For every sprite find a free space in panel:
for (Spritesheet sheet : spritesheets) {
i = 0;
while ((img = sheet.getImage(i)) != null) {
i = -1;
while ((img = sheet.getImage(++i)) != null) {
if (SpriteUtils.checkIsImageEmpty(img)) {
continue;
}
IconButton button = new IconButton(img, sheet.id, i);
group.add(button);
if (sheet.spriteWidth == STD_WIDTH && sheet.spriteHeight == STD_HEIGHT) {
@@ -120,7 +115,7 @@ public class SpriteChooser extends JDialog {
c.gridx = 0;
c.gridy++;
}
nextFreeSlot.setLocation(c.gridx, c.gridy);
nextFreeSlot.setLocation(c.gridx, c.gridy);
} else {
c.gridwidth = (sheet.spriteWidth / STD_WIDTH) + (sheet.spriteWidth % STD_WIDTH == 0 ? 0 : 1);
c.gridheight = (sheet.spriteHeight / STD_HEIGHT) + (sheet.spriteHeight % STD_HEIGHT == 0 ? 0 : 1);
@@ -131,14 +126,20 @@ public class SpriteChooser extends JDialog {
for (int y = c.gridy; y < c.gridy + c.gridwidth; y++) {
if (reservedSlots.contains(new Point(x, y))) {
slotOk = false;
break;
}
}
if (!slotOk) {
break;
}
}
if (slotOk && c.gridx + c.gridwidth > MAX_PER_ROW) {
if (c.gridx + c.gridwidth > MAX_PER_ROW) {
c.gridx = 0;
c.gridy++;
slotOk = false;
}
} else if (!slotOk) {
c.gridx++;
}
}
pane.add(button, c);
for (int x = c.gridx; x < c.gridx + c.gridwidth; x++) {
@@ -157,15 +158,14 @@ public class SpriteChooser extends JDialog {
c.gridx = 0;
c.gridy++;
}
nextFreeSlot.setLocation(c.gridx, c.gridy);
nextFreeSlot.setLocation(c.gridx, c.gridy);
}
i++;
}
}
// ok = new JButton("Ok");
// cancel = new JButton("Cancel");
c.gridx = 0;
boolean emptyLine = false;
while (!emptyLine) {
@@ -178,7 +178,7 @@ public class SpriteChooser extends JDialog {
}
}
}
// JPanel buttonPane = new JPanel();
// buttonPane.add(cancel, BorderLayout.WEST);
// buttonPane.add(ok, BorderLayout.EAST);
@@ -190,7 +190,7 @@ public class SpriteChooser extends JDialog {
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
wrapper.add(scroller, BorderLayout.CENTER);
// wrapper.add(buttonPane, BorderLayout.SOUTH);
// ok.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
@@ -200,7 +200,7 @@ public class SpriteChooser extends JDialog {
// if (listener != null) listener.iconSelected(selectedIconId);
// }
// });
// cancel.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
@@ -210,21 +210,21 @@ public class SpriteChooser extends JDialog {
// if (listener != null) listener.iconSelected(null);
// }
// });
setContentPane(wrapper);
}
private SpriteChooser.SelectionListener listener = null;
public void setSelectionListener(SpriteChooser.SelectionListener l) {
listener = l;
}
public class IconButton extends JToggleButton {
private static final long serialVersionUID = 7559407153561178455L;
public String sheetId;
public int spriteIndex;
@@ -232,12 +232,12 @@ public class SpriteChooser extends JDialog {
super(new ImageIcon(img));
this.sheetId = sheetId;
this.spriteIndex = spriteIndex;
setToolTipText(sheetId+":"+spriteIndex);
setToolTipText(sheetId + ":" + spriteIndex);
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (IconButton.this.isSelected()) {
selectedIconId = IconButton.this.sheetId+":"+IconButton.this.spriteIndex;
selectedIconId = IconButton.this.sheetId + ":" + IconButton.this.spriteIndex;
SpriteChooser.this.setVisible(false);
SpriteChooser.this.dispose();
if (listener != null) listener.iconSelected(selectedIconId);
@@ -246,9 +246,9 @@ public class SpriteChooser extends JDialog {
});
}
}
public static interface SelectionListener {
public void iconSelected(String selected);
}
}

View File

@@ -100,6 +100,20 @@ public class SpritesheetEditor extends Editor {
});
buttonPane.add(openImage, JideBoxLayout.FIX);
buttonPane.add(getWarningLabel(), JideBoxLayout.FIX);
final JButton bookmark = new JButton(new ImageIcon(sheet.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon()));
buttonPane.add(bookmark, JideBoxLayout.FIX);
bookmark.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (target.bookmark == null) {
target.getProject().bookmark(target);
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon()));
} else {
target.bookmark.delete();
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon()));
}
}
});
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
addLabelField(pane, "Spritesheet ID: ", sheet.id);

Some files were not shown because too many files have changed in this diff Show More