├── .gitignore
├── LICENSE
├── NOTICE
├── README.md
├── lib
├── bitmap.jar
├── gson-2.8.5.jar
├── luaj-jse-3.0.1.jar
└── vulcdataformat.jar
├── res
└── res
│ ├── font.fv3
│ ├── icon.png
│ ├── icons
│ ├── editor
│ │ ├── map_editor.png
│ │ ├── sprite
│ │ │ ├── scope_1.png
│ │ │ └── scope_2.png
│ │ ├── sprite_editor.png
│ │ └── tool
│ │ │ ├── bucket.png
│ │ │ ├── pencil.png
│ │ │ ├── pickup.png
│ │ │ └── select.png
│ ├── redo.png
│ ├── save.png
│ ├── selected.png
│ ├── shell.png
│ └── undo.png
│ └── templates
│ └── template.zip
└── src
└── vulc
└── luag
├── Console.java
├── LoggerSetup.java
├── editor
├── Editor.java
├── gui
│ └── AtlasPreview.java
├── map
│ ├── MapCompiler.java
│ ├── MapEditor.java
│ └── gui
│ │ ├── MapAtlasPreview.java
│ │ ├── MapPreview.java
│ │ ├── MapSizePanel.java
│ │ └── MapSizeTextBox.java
└── sprite
│ ├── SpriteEditor.java
│ ├── gui
│ ├── SpriteAtlasPreview.java
│ ├── SpriteColorbar.java
│ ├── SpriteColorbarPalette.java
│ ├── SpritePreview.java
│ ├── SpriteScopeButton.java
│ ├── SpriteScopeSelector.java
│ ├── SpriteToolButton.java
│ └── SpriteToolbar.java
│ ├── history
│ └── History.java
│ └── tool
│ ├── BucketTool.java
│ ├── PencilTool.java
│ ├── PickupTool.java
│ ├── SelectTool.java
│ ├── SpriteTool.java
│ └── SpriteToolkit.java
├── game
├── Game.java
├── GameSounds.java
├── LuaScriptCore.java
├── cartridge
│ └── Cartridge.java
├── interfaces
│ ├── Interface001.java
│ └── LuaInterface.java
├── map
│ └── Map.java
└── save
│ └── SaveSystem.java
├── gfx
├── Colors.java
├── ConsoleFrame.java
├── Icons.java
├── Screen.java
├── gui
│ ├── GUIButton.java
│ ├── GUIComponent.java
│ ├── GUILabel.java
│ ├── GUIMainPanel.java
│ ├── GUIPanel.java
│ └── GUITextBox.java
└── panel
│ ├── BootPanel.java
│ ├── DeathPanel.java
│ ├── EditorPanel.java
│ ├── GamePanel.java
│ ├── Panel.java
│ └── ShellPanel.java
├── input
├── FullScreenListener.java
└── InputHandler.java
├── sfx
└── Sound.java
└── shell
├── Shell.java
├── ShellChar.java
├── ShellRow.java
└── command
├── ClsCommand.java
├── EditCommand.java
├── ExitCommand.java
├── FilesCommand.java
├── HelpCommand.java
├── LogCommand.java
├── ModeCommand.java
├── PackCommand.java
├── RunCommand.java
├── SetupCommand.java
├── ShellCommand.java
└── VerCommand.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /.settings/
3 | /.project
4 | /.classpath
5 |
6 | /luag*.log*
7 | /*.sav
8 | /console-userdata/
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | LuaG-Console
2 | Copyright 2019-2022 Vulcalien
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | # LuaG Console
3 | LuaG is a virtual console that allows you to build a game very quickly using the lua language.
4 | The console offers tools for developers, like the integrated editors for the map and the sprites!
5 | LuaG is always getting updates!
6 |
7 | ## Getting Started
8 | First of all, [download the console](https://github.com/Vulcalien/LuaG-Console/wiki/Download).
9 | **If you are a developer** open the console, type `mode d` and then `setup`. Now you have blank game files, so you can start programming!
10 | Just type `files`, find the `script` folder and there will go all your code!
11 |
12 | **If you want to play** download a game cartridge, put it in the same folder of the *.jar* file, type `run {cartridge-name}` in the console and enjoy!
13 |
14 | ## How to create a Game
15 | Creating a Game in LuaG is very easy!
16 | All Game files are stored inside the folder `console-userdata` (the one you open with the `files` command). Read the [documentation](https://github.com/Vulcalien/LuaG-Console/wiki/Lua-Script) about the game scripting.
17 | You can use useful tools, such as the integrated editors (map and sprites). Just remember to switch to *developer mode* using `mode d`.
18 | In this mode you can **run the game directly** without packing it into a cartridge. You can also exit the game pressing `F8`.
19 | Type `help` to get a list of all the commands you can use.
20 |
21 | ## Game Deployment
22 | To deploy a LuaG game, you have first to create a `cartridge`. You can do this using `pack {cartridge-name}`.
23 | Now, just publish the cartridge! (I suggest you to leave a link to the [download page](https://github.com/Vulcalien/LuaG-Console/wiki/Download) of LuaG console).
24 |
25 | ## License
26 | The Console is released under Apache 2.0 license. See [License](LICENSE).
27 |
28 | ## Built With
29 | - [Bitmap Utility](https://github.com/Vulcalien/Bitmap-Utility) by [Vulcalien](https://github.com/Vulcalien/)
30 | - [Gson](https://github.com/google/gson) by [Google](https://github.com/google)
31 | - [LuaJ](http://www.luaj.org/luaj.html) by [LuaJ](http://www.luaj.org/)
32 |
33 | ## More Details
34 | [Click here](https://github.com/Vulcalien/LuaG-Console/wiki) to see the wiki.
35 |
--------------------------------------------------------------------------------
/lib/bitmap.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/lib/bitmap.jar
--------------------------------------------------------------------------------
/lib/gson-2.8.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/lib/gson-2.8.5.jar
--------------------------------------------------------------------------------
/lib/luaj-jse-3.0.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/lib/luaj-jse-3.0.1.jar
--------------------------------------------------------------------------------
/lib/vulcdataformat.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/lib/vulcdataformat.jar
--------------------------------------------------------------------------------
/res/res/font.fv3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/font.fv3
--------------------------------------------------------------------------------
/res/res/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icon.png
--------------------------------------------------------------------------------
/res/res/icons/editor/map_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/map_editor.png
--------------------------------------------------------------------------------
/res/res/icons/editor/sprite/scope_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/sprite/scope_1.png
--------------------------------------------------------------------------------
/res/res/icons/editor/sprite/scope_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/sprite/scope_2.png
--------------------------------------------------------------------------------
/res/res/icons/editor/sprite_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/sprite_editor.png
--------------------------------------------------------------------------------
/res/res/icons/editor/tool/bucket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/tool/bucket.png
--------------------------------------------------------------------------------
/res/res/icons/editor/tool/pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/tool/pencil.png
--------------------------------------------------------------------------------
/res/res/icons/editor/tool/pickup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/tool/pickup.png
--------------------------------------------------------------------------------
/res/res/icons/editor/tool/select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/editor/tool/select.png
--------------------------------------------------------------------------------
/res/res/icons/redo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/redo.png
--------------------------------------------------------------------------------
/res/res/icons/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/save.png
--------------------------------------------------------------------------------
/res/res/icons/selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/selected.png
--------------------------------------------------------------------------------
/res/res/icons/shell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/shell.png
--------------------------------------------------------------------------------
/res/res/icons/undo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/icons/undo.png
--------------------------------------------------------------------------------
/res/res/templates/template.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vulcalien/LuaG-Console-java/b1bdd66a69301d76174f64f66c147b26f5efa5ff/res/res/templates/template.zip
--------------------------------------------------------------------------------
/src/vulc/luag/Console.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2019-2022 Vulcalien
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy
6 | * of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | ******************************************************************************/
16 | package vulc.luag;
17 |
18 | import java.awt.Canvas;
19 | import java.awt.Dimension;
20 | import java.awt.Graphics;
21 | import java.awt.Insets;
22 | import java.awt.Toolkit;
23 | import java.awt.image.BufferStrategy;
24 | import java.awt.image.BufferedImage;
25 | import java.awt.image.DataBufferInt;
26 | import java.io.File;
27 | import java.net.URISyntaxException;
28 | import java.util.logging.Level;
29 | import java.util.logging.Logger;
30 |
31 | import javax.swing.JFrame;
32 |
33 | import vulc.luag.gfx.ConsoleFrame;
34 | import vulc.luag.gfx.Screen;
35 | import vulc.luag.gfx.panel.BootPanel;
36 | import vulc.luag.gfx.panel.DeathPanel;
37 | import vulc.luag.gfx.panel.GamePanel;
38 | import vulc.luag.gfx.panel.Panel;
39 | import vulc.luag.gfx.panel.ShellPanel;
40 | import vulc.luag.input.FullScreenListener;
41 | import vulc.luag.shell.Shell;
42 |
43 | /**
44 | * Open Source since: 20.06.2019
45 | * GitHub: https://github.com/Vulcalien/LuaG-Console
46 | * Author: Vulcalien
47 | *
48 | *
Used Libraries
49 | *
50 | * - 'Bitmap Utility' by Vulcalien (Copyright 2019 Vulcalien - https://github.com/Vulcalien/Bitmap-Utility/blob/master/LICENSE)
51 | * - 'Gson' by Google (Copyright 2008-2011 Google Inc. - https://github.com/google/gson/blob/master/LICENSE)
52 | * - 'LuaJ' by LuaJ (Copyright (c) 2007-2013 LuaJ - http://luaj.sourceforge.net/license.txt)
53 | * - 'VulcDataFormat' by Vulcalien (Copyright 2019-2020 Vulcalien - https://github.com/Vulcalien/VulcDataFormat/blob/master/LICENSE)
54 | *
55 | */
56 | public class Console extends Canvas implements Runnable {
57 |
58 | public enum Mode {
59 | USER_GAME, USER_SHELL, DEVELOPER
60 | }
61 |
62 | private static final long serialVersionUID = 1L;
63 |
64 | public static final Object DONT_STOP_LOCK = new Object();
65 |
66 | public static final String NAME = "LuaG Console";
67 | public static final String VERSION = "0.7.0-WIP";
68 | public static final String COPYRIGHT = "Copyright 2022 Vulcalien";
69 |
70 | public static final int WIDTH = 160, HEIGHT = 160;
71 | public static int scaledWidth, scaledHeight;
72 | public static int xOffset, yOffset;
73 | public static boolean isFullScreen;
74 |
75 | public static final Logger LOGGER = Logger.getLogger(Console.class.getName());
76 | public static String rootDirectory;
77 | public static String logFile;
78 |
79 | public static final Screen SCREEN = new Screen(WIDTH, HEIGHT);
80 | public static Panel currentPanel;
81 |
82 | public static String cartridge;
83 | public static Mode mode;
84 |
85 | public static Console instance;
86 | public static int ticks = 0;
87 |
88 | private static boolean running = false;
89 | private static Thread thread;
90 |
91 | public static ConsoleFrame frame;
92 |
93 | private final BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
94 | private final int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
95 |
96 | public void run() {
97 | int ticksPerSecond = 60;
98 |
99 | long nanosPerTick = 1_000_000_000 / ticksPerSecond;
100 | long unprocessedNanos = 0;
101 | long lastTime = System.nanoTime();
102 |
103 | while(running) {
104 | long now = System.nanoTime();
105 | long passedTime = now - lastTime;
106 | lastTime = now;
107 |
108 | if(passedTime < 0) passedTime = 0;
109 | if(passedTime > 1_000_000_000) passedTime = 1_000_000_000;
110 |
111 | unprocessedNanos += passedTime;
112 |
113 | while(unprocessedNanos >= nanosPerTick) {
114 | unprocessedNanos -= nanosPerTick;
115 |
116 | try {
117 | tick();
118 | ticks++;
119 | } catch(Throwable e) {
120 | LOGGER.log(Level.SEVERE, "Console Error", e);
121 | System.exit(1);
122 | }
123 | }
124 |
125 | try {
126 | Thread.sleep(4);
127 | } catch(InterruptedException e) {
128 | e.printStackTrace();
129 | }
130 | }
131 | }
132 |
133 | public static void start() {
134 | if(running) return;
135 | running = true;
136 |
137 | LOGGER.info("Console: start");
138 |
139 | thread = new Thread(instance);
140 | thread.start();
141 | }
142 |
143 | public static void stop() {
144 | if(!running) return;
145 | running = false;
146 |
147 | LOGGER.info("Console: stop");
148 |
149 | try {
150 | thread.join();
151 | } catch(InterruptedException e) {
152 | e.printStackTrace();
153 | }
154 | }
155 |
156 | private void init(String[] args) {
157 | requestFocus();
158 |
159 | if(args.length > 0) {
160 | if(args[0].equals("-dev")) {
161 | mode = Mode.DEVELOPER;
162 | } else {
163 | // this is not relative to root: it should be an argument passed automatically
164 | cartridge = args[0];
165 | mode = Mode.USER_GAME;
166 | }
167 | } else {
168 | mode = Mode.USER_SHELL;
169 | }
170 |
171 | LOGGER.info("Startup mode: " + mode);
172 |
173 | Panel nextPanel = null;
174 |
175 | if(mode == Mode.DEVELOPER || mode == Mode.USER_SHELL) {
176 | Shell.init();
177 | nextPanel = new ShellPanel();
178 | } else if(mode == Mode.USER_GAME) {
179 | nextPanel = new GamePanel();
180 | }
181 |
182 | BootPanel bootPanel = new BootPanel();
183 | bootPanel.nextPanel = nextPanel;
184 | currentPanel = bootPanel;
185 | currentPanel.init();
186 | }
187 |
188 | private void tick() {
189 | currentPanel.tick();
190 |
191 | frame.checkSize();
192 | render();
193 | }
194 |
195 | private void render() {
196 | BufferStrategy bs = getBufferStrategy();
197 | if(bs == null) {
198 | createBufferStrategy(3);
199 | return;
200 | }
201 |
202 | for(int i = 0; i < pixels.length; i++) {
203 | pixels[i] = SCREEN.raster.getPixel(i);
204 | }
205 |
206 | Graphics g = bs.getDrawGraphics();
207 | g.clearRect(0, 0, instance.getWidth(), instance.getHeight());
208 | g.drawImage(img, xOffset, yOffset, scaledWidth, scaledHeight, null);
209 | g.dispose();
210 | bs.show();
211 | }
212 |
213 | public static void switchToPanel(Panel panel) {
214 | LOGGER.info("Switching to panel: " + panel.getClass().getSimpleName());
215 |
216 | if(currentPanel != null) currentPanel.remove();
217 | currentPanel = panel;
218 | panel.init();
219 | panel.onShow();
220 | }
221 |
222 | public static void die(String text) {
223 | LOGGER.severe("Console die:\n" + text);
224 |
225 | if(mode == Mode.DEVELOPER || mode == Mode.USER_SHELL) {
226 | switchToPanel(new ShellPanel());
227 | Shell.write(text + "\n\n", Shell.ERROR_FOREGROUND);
228 | } else {
229 | switchToPanel(new DeathPanel(text));
230 | }
231 | }
232 |
233 | public static void main(String[] args) {
234 | startupOperations();
235 | LOGGER.info("Starting Console...");
236 |
237 | Toolkit.getDefaultToolkit().setDynamicLayout(false);
238 |
239 | instance = new Console();
240 | initFrame(false);
241 | instance.init(args);
242 |
243 | frame.setVisible(true);
244 | start();
245 |
246 | instance.addKeyListener(new FullScreenListener());
247 | }
248 |
249 | private static void startupOperations() {
250 | if(Console.class.getResource("Console.class").toString().startsWith("jar")) {
251 | try {
252 | File jarFile = new File(Console.class.getProtectionDomain()
253 | .getCodeSource()
254 | .getLocation()
255 | .toURI());
256 | rootDirectory = jarFile.getParent() + "/";
257 | } catch(URISyntaxException e) {
258 | e.printStackTrace();
259 | }
260 | } else {
261 | rootDirectory = "./";
262 | }
263 |
264 | LoggerSetup.setup(LOGGER, rootDirectory);
265 | }
266 |
267 | private static void setInitialScale() {
268 | int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
269 |
270 | // by default, the console's height is half of the screen
271 | double newScale = (double) screenHeight / HEIGHT / 2;
272 |
273 | updateScaledSize((int) (WIDTH * newScale), (int) (HEIGHT * newScale));
274 | instance.setSize(scaledWidth, scaledHeight);
275 | frame.pack();
276 | }
277 |
278 | public static void updateScaledSize(int width, int height) {
279 | // find lowest scale and use it on both sides
280 | int minScaled, minScreen;
281 | if(width * Console.HEIGHT < height * Console.WIDTH) {
282 | minScaled = width;
283 | minScreen = Console.WIDTH;
284 | } else {
285 | minScaled = height;
286 | minScreen = Console.HEIGHT;
287 | }
288 |
289 | scaledWidth = Console.WIDTH * minScaled / minScreen;
290 | scaledHeight = Console.HEIGHT * minScaled / minScreen;
291 |
292 | xOffset = (width - scaledWidth) / 2;
293 | yOffset = (height - scaledHeight) / 2;
294 | }
295 |
296 | private static void initFrame(boolean fullScreen) {
297 | frame = new ConsoleFrame();
298 | frame.init();
299 | frame.add(instance);
300 |
301 | isFullScreen = fullScreen;
302 |
303 | if(fullScreen) {
304 | frame.setUndecorated(true);
305 | frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
306 | } else {
307 | // set minimum size (it is console's size not scaled + insets)
308 | frame.pack(); // this sets the insets of the frame
309 |
310 | Insets insets = frame.getInsets();
311 | frame.setMinimumSize(new Dimension(WIDTH + insets.left + insets.right,
312 | HEIGHT + insets.top + insets.bottom));
313 |
314 | setInitialScale();
315 | frame.setLocationRelativeTo(null);
316 | }
317 | }
318 |
319 | public static void switchFullScreen() {
320 | stop();
321 |
322 | frame.setVisible(false);
323 |
324 | // this changes the value of isFullScreen
325 | initFrame(!isFullScreen);
326 |
327 | frame.setVisible(true);
328 | instance.requestFocus();
329 |
330 | start();
331 | }
332 |
333 | }
334 |
--------------------------------------------------------------------------------
/src/vulc/luag/LoggerSetup.java:
--------------------------------------------------------------------------------
1 | package vulc.luag;
2 |
3 | import java.io.File;
4 | import java.util.Locale;
5 | import java.util.logging.FileHandler;
6 | import java.util.logging.Level;
7 | import java.util.logging.Logger;
8 | import java.util.logging.SimpleFormatter;
9 |
10 | public abstract class LoggerSetup {
11 |
12 | public static final void setup(Logger logger, String folder) {
13 | logger.setLevel(Level.ALL);
14 | Locale.setDefault(Locale.ENGLISH);
15 | try {
16 | // fallback value, in case a good filename is not found
17 | String fileName = folder + "luag.log";
18 |
19 | for(int i = 0; i < 100; i++) {
20 | // first, try with "luag.log" then try adding numbers
21 | fileName = folder + "luag" + (i == 0 ? "" : "-" + i) + ".log";
22 | File file = new File(fileName);
23 |
24 | // if does not exist or is a file and is not locked
25 | if(!file.exists() || (file.isFile() && file.delete())) {
26 | break;
27 | }
28 | }
29 |
30 | Console.logFile = fileName;
31 | FileHandler fh = new FileHandler(fileName);
32 | fh.setFormatter(new SimpleFormatter());
33 | logger.addHandler(fh);
34 | } catch(Exception e) {
35 | e.printStackTrace();
36 | }
37 |
38 | Runtime.getRuntime().addShutdownHook(new Thread() {
39 | public void run() {
40 | logger.info("Shutting down Console");
41 | }
42 | });
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/Editor.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor;
2 |
3 | import vulc.luag.gfx.gui.GUIPanel;
4 | import vulc.luag.gfx.panel.EditorPanel;
5 | import vulc.luag.input.InputHandler;
6 |
7 | public abstract class Editor {
8 |
9 | public final EditorPanel editorPanel;
10 |
11 | protected final GUIPanel guiPanel;
12 | protected final InputHandler input;
13 |
14 | public Editor(EditorPanel editorPanel, int x, int y, int w, int h) {
15 | this.editorPanel = editorPanel;
16 | this.guiPanel = new GUIPanel(x, y, w, h);
17 | this.input = editorPanel.mainPanel.input;
18 | }
19 |
20 | public void onShow() {
21 | editorPanel.mainPanel.add(this.guiPanel);
22 | }
23 |
24 | public void tick() {
25 | }
26 |
27 | public abstract String getTitle();
28 |
29 | public void remove() {
30 | editorPanel.mainPanel.remove(this.guiPanel);
31 | }
32 |
33 | public boolean shouldSave() {
34 | return false;
35 | }
36 |
37 | public void onSave() {
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/gui/AtlasPreview.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.gui;
2 |
3 | import vulc.luag.game.Game;
4 | import vulc.luag.gfx.Icons;
5 | import vulc.luag.gfx.gui.GUIPanel;
6 |
7 | public class AtlasPreview extends GUIPanel {
8 |
9 | private final Game game;
10 |
11 | private int animationTicks = 0;
12 | protected int atlasOffset = 0;
13 | protected int selected = 0;
14 | public int scope = 1;
15 |
16 | public AtlasPreview(int x, int y, int w, int h, Game game) {
17 | super(x, y, w, h);
18 | this.game = game;
19 | }
20 |
21 | public void tick() {
22 | animationTicks++;
23 | }
24 |
25 | public void drawComponents() {
26 | screen.draw(game.atlas.getSubimage(0, atlasOffset * Game.SPR_SIZE, w, h), 0, 0);
27 |
28 | int xSpr = selected % 16;
29 | int ySpr = ((selected / 16) - atlasOffset);
30 |
31 | int transparency = animationTicks / 50 % 2 == 0 ? 0xaa : 0xdd;
32 |
33 | screen.drawBool(Icons.SELECTED.getScaled(scope), 0xffffff, transparency,
34 | xSpr * Game.SPR_SIZE,
35 | ySpr * Game.SPR_SIZE);
36 | }
37 |
38 | public void onMouseDown(int xMouse, int yMouse) {
39 | int xs = xMouse / Game.SPR_SIZE;
40 | int ys = yMouse / Game.SPR_SIZE + atlasOffset;
41 |
42 | setSelected(xs, ys);
43 | }
44 |
45 | public void onMouseScroll(int xMouse, int yMouse, int count) {
46 | int newOffset = atlasOffset + count;
47 | if(newOffset >= 0 && newOffset + h / Game.SPR_SIZE <= 16) {
48 | atlasOffset = newOffset;
49 | }
50 | }
51 |
52 | public void setSelected(int xs, int ys) {
53 | if(xs + scope > 16) xs = 16 - scope;
54 | if(ys + scope > 16) ys = 16 - scope;
55 |
56 | selected = xs + ys * 16; // 16 = atlas.width (in sprites)
57 | }
58 |
59 | public void setScope(int scope) {
60 | this.scope = scope;
61 |
62 | // check if the selected area is out of bounds
63 | int xs = selected % 16;
64 | int ys = selected / 16;
65 |
66 | setSelected(xs, ys);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/MapCompiler.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.DataOutputStream;
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 |
9 | import vulc.luag.Console;
10 | import vulc.luag.game.Game;
11 | import vulc.luag.game.map.Map;
12 |
13 | public abstract class MapCompiler {
14 |
15 | public static void compile(Map map) {
16 | synchronized(Console.DONT_STOP_LOCK) {
17 | try {
18 | File file = new File(Game.MAP_FILE);
19 | file.createNewFile();
20 |
21 | DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
22 |
23 | int w = map.width;
24 | int h = map.height;
25 |
26 | out.writeInt(w);
27 | out.writeInt(h);
28 |
29 | for(int i = 0; i < map.tiles.length; i++) {
30 | out.writeByte(map.tiles[i] + 128);
31 | }
32 | out.close();
33 | } catch(IOException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/MapEditor.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map;
2 |
3 | import java.awt.event.KeyEvent;
4 |
5 | import vulc.luag.editor.Editor;
6 | import vulc.luag.editor.map.gui.MapAtlasPreview;
7 | import vulc.luag.editor.map.gui.MapPreview;
8 | import vulc.luag.editor.map.gui.MapSizePanel;
9 | import vulc.luag.editor.map.gui.MapSizeTextBox;
10 | import vulc.luag.game.Game;
11 | import vulc.luag.game.map.Map;
12 | import vulc.luag.gfx.gui.GUIPanel;
13 | import vulc.luag.gfx.panel.EditorPanel;
14 | import vulc.luag.input.InputHandler.Key;
15 | import vulc.luag.input.InputHandler.KeyType;
16 |
17 | public class MapEditor extends Editor {
18 |
19 | private final Key moveUp;
20 | private final Key moveLeft;
21 | private final Key moveDown;
22 | private final Key moveRight;
23 |
24 | public int xOffset = 0, yOffset = 0;
25 | public int selectedTile = 0;
26 |
27 | public boolean shouldSaveContent = false;
28 |
29 | public MapEditor(EditorPanel editorPanel, int x, int y, int w, int h) {
30 | super(editorPanel, x, y, w, h);
31 |
32 | moveUp = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_W);
33 | moveLeft = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_A);
34 | moveDown = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_S);
35 | moveRight = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_D);
36 |
37 | // INTERFACE
38 | guiPanel.background = 0x000000;
39 |
40 | GUIPanel previewPanel = new MapPreview(5, 5, guiPanel.w - 10, 10 * Game.SPR_SIZE,
41 | this);
42 | guiPanel.add(previewPanel);
43 |
44 | int wAtlas = editorPanel.game.atlas.width;
45 | int hAtlas = 4 * Game.SPR_SIZE;
46 | MapAtlasPreview atlasPreview = new MapAtlasPreview((guiPanel.w - wAtlas) / 2, guiPanel.h - hAtlas - 5,
47 | wAtlas, hAtlas,
48 | this);
49 | guiPanel.add(atlasPreview);
50 |
51 | GUIPanel sizePanel = new MapSizePanel(atlasPreview.x, previewPanel.y + previewPanel.h + 3,
52 | atlasPreview.w, 12,
53 | this);
54 | guiPanel.add(sizePanel);
55 | }
56 |
57 | public void tick() {
58 | int moveSpeed = 2;
59 | if(moveUp.isKeyDown()) yOffset -= moveSpeed;
60 | if(moveLeft.isKeyDown()) xOffset -= moveSpeed;
61 | if(moveDown.isKeyDown()) yOffset += moveSpeed;
62 | if(moveRight.isKeyDown()) xOffset += moveSpeed;
63 | }
64 |
65 | public void resizeMap(int newSide, boolean sideFlag) {
66 | Map oldMap = editorPanel.game.map;
67 |
68 | int w = (sideFlag == MapSizeTextBox.WIDTH ? newSide : oldMap.width);
69 | int h = (sideFlag == MapSizeTextBox.HEIGHT ? newSide : oldMap.height);
70 | Map newMap = new Map(w, h);
71 |
72 | x_loop:
73 | for(int x = 0; x < oldMap.width; x++) {
74 | if(x >= w) break x_loop;
75 |
76 | y_loop:
77 | for(int y = 0; y < oldMap.height; y++) {
78 | if(y >= h) break y_loop;
79 |
80 | newMap.setTile(x, y, oldMap.getTile(x, y));
81 | }
82 | }
83 |
84 | editorPanel.game.map = newMap;
85 | shouldSaveContent = true;
86 | }
87 |
88 | public boolean shouldSave() {
89 | return shouldSaveContent;
90 | }
91 |
92 | public void onSave() {
93 | MapCompiler.compile(editorPanel.game.map);
94 | shouldSaveContent = false;
95 | }
96 |
97 | public String getTitle() {
98 | return "Map Editor";
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/gui/MapAtlasPreview.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map.gui;
2 |
3 | import vulc.luag.editor.gui.AtlasPreview;
4 | import vulc.luag.editor.map.MapEditor;
5 |
6 | public class MapAtlasPreview extends AtlasPreview {
7 |
8 | private final MapEditor editor;
9 |
10 | public MapAtlasPreview(int x, int y, int w, int h, MapEditor editor) {
11 | super(x, y, w, h, editor.editorPanel.game);
12 | this.editor = editor;
13 | }
14 |
15 | public void onMouseDown(int xMouse, int yMouse) {
16 | super.onMouseDown(xMouse, yMouse);
17 | editor.selectedTile = selected;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/gui/MapPreview.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map.gui;
2 |
3 | import vulc.luag.editor.map.MapEditor;
4 | import vulc.luag.game.Game;
5 | import vulc.luag.gfx.Colors;
6 | import vulc.luag.gfx.Screen;
7 | import vulc.luag.gfx.gui.GUIPanel;
8 |
9 | public class MapPreview extends GUIPanel {
10 |
11 | private final MapEditor editor;
12 | private final Game game;
13 |
14 | private int xPointed, yPointed;
15 |
16 | public MapPreview(int x, int y, int w, int h, MapEditor editor) {
17 | super(x, y, w, h);
18 | this.editor = editor;
19 | this.game = editor.editorPanel.game;
20 |
21 | background = Colors.BACKGROUND_1;
22 | }
23 |
24 | protected void drawComponents() {
25 | super.drawComponents();
26 | game.map.render(this.screen, game, editor.xOffset, editor.yOffset, 1);
27 |
28 | String xText = "x: " + xPointed;
29 | String yText = "y: " + yPointed;
30 |
31 | int wPanel = Math.max(Screen.FONT.widthOf(xText), Screen.FONT.widthOf(yText));
32 | int hPanel = Screen.FONT.getHeight() * 2 + 1;
33 |
34 | screen.fill(w - wPanel, h - hPanel, w, h, Colors.BACKGROUND_1);
35 |
36 | screen.write(xText, Colors.FOREGROUND_1,
37 | w - wPanel, h - hPanel);
38 | screen.write(yText, Colors.FOREGROUND_1,
39 | w - wPanel, h - Screen.FONT.getHeight());
40 | }
41 |
42 | public void onMouseDown(int xMouse, int yMouse) {
43 | super.onMouseDown(xMouse, yMouse);
44 |
45 | int xt = Math.floorDiv(xMouse + editor.xOffset, Game.SPR_SIZE);
46 | int yt = Math.floorDiv(yMouse + editor.yOffset, Game.SPR_SIZE);
47 |
48 | if(xt < 0 || yt < 0 || xt >= game.map.width || yt >= game.map.height) return;
49 |
50 | if(game.map.getTile(xt, yt) != editor.selectedTile) {
51 | game.map.setTile(xt, yt, editor.selectedTile);
52 | editor.shouldSaveContent = true;
53 | }
54 | }
55 |
56 | public void onMouseInside(int xMouse, int yMouse) {
57 | this.xPointed = Math.floorDiv(xMouse + editor.xOffset, Game.SPR_SIZE);
58 | this.yPointed = Math.floorDiv(yMouse + editor.yOffset, Game.SPR_SIZE);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/gui/MapSizePanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map.gui;
2 |
3 | import vulc.luag.editor.map.MapEditor;
4 | import vulc.luag.game.map.Map;
5 | import vulc.luag.gfx.Colors;
6 | import vulc.luag.gfx.Screen;
7 | import vulc.luag.gfx.gui.GUILabel;
8 | import vulc.luag.gfx.gui.GUIPanel;
9 |
10 | public class MapSizePanel extends GUIPanel {
11 |
12 | public MapSizePanel(int x, int y, int w, int h, MapEditor editor) {
13 | super(x, y, w, h);
14 |
15 | Map map = editor.editorPanel.game.map;
16 |
17 | int textBoxWidth = (Screen.FONT.widthOf(' ') + Screen.FONT.getLetterSpacing()) * MapSizeTextBox.N_CHARS + 1;
18 |
19 | GUIPanel wPanel = new GUIPanel(0, 0, w / 2, h);
20 | {
21 | wPanel.background = Colors.BACKGROUND_0;
22 |
23 | GUILabel label = new GUILabel(0, 0, Screen.FONT.widthOf("width"), h);
24 | label.textColor = Colors.FOREGROUND_0;
25 | label.text = "width";
26 | wPanel.add(label);
27 |
28 | MapSizeTextBox textBox = new MapSizeTextBox(label.w + 3, 1,
29 | textBoxWidth, h - 2,
30 | editor, MapSizeTextBox.WIDTH);
31 | textBox.text = map.width + "";
32 | wPanel.add(textBox);
33 | }
34 | this.add(wPanel);
35 |
36 | GUIPanel hPanel = new GUIPanel(w / 2, 0, w / 2, h);
37 | {
38 | hPanel.background = Colors.BACKGROUND_0;
39 |
40 | GUILabel label = new GUILabel(0, 0, Screen.FONT.widthOf("height"), h);
41 | label.textColor = Colors.FOREGROUND_0;
42 | label.text = "height";
43 | hPanel.add(label);
44 |
45 | MapSizeTextBox textBox = new MapSizeTextBox(label.w + 3, 1,
46 | textBoxWidth, h - 2,
47 | editor, MapSizeTextBox.HEIGHT);
48 | textBox.text = map.height + "";
49 | hPanel.add(textBox);
50 | }
51 | this.add(hPanel);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/map/gui/MapSizeTextBox.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.map.gui;
2 |
3 | import vulc.luag.editor.map.MapEditor;
4 | import vulc.luag.gfx.gui.GUITextBox;
5 |
6 | public class MapSizeTextBox extends GUITextBox {
7 |
8 | public static final boolean WIDTH = false, HEIGHT = true;
9 | public static final int N_CHARS = 4;
10 |
11 | private final MapEditor editor;
12 | private final boolean side;
13 |
14 | public MapSizeTextBox(int x, int y, int w, int h, MapEditor editor, boolean side) {
15 | super(x, y, w, h);
16 | this.editor = editor;
17 | this.side = side;
18 |
19 | acceptedText = GUITextBox.DEC_ONLY;
20 | nChars = N_CHARS;
21 | opaque = true;
22 | background = 0xffffff;
23 | textColor = 0x000000;
24 | }
25 |
26 | public void onEnterPress() {
27 | super.onEnterPress();
28 |
29 | int value;
30 | if(text.equals("")) {
31 | value = 0;
32 | } else {
33 | value = Integer.parseInt(text);
34 | if(value > 256) {
35 | value = 256;
36 | }
37 | }
38 | text = "" + value;
39 |
40 | editor.resizeMap(value, side);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/SpriteEditor.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite;
2 |
3 | import java.awt.event.KeyEvent;
4 | import java.awt.image.BufferedImage;
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import javax.imageio.ImageIO;
11 |
12 | import vulc.bitmap.Bitmap;
13 | import vulc.luag.editor.Editor;
14 | import vulc.luag.editor.sprite.gui.SpriteAtlasPreview;
15 | import vulc.luag.editor.sprite.gui.SpriteColorbar;
16 | import vulc.luag.editor.sprite.gui.SpritePreview;
17 | import vulc.luag.editor.sprite.gui.SpriteScopeSelector;
18 | import vulc.luag.editor.sprite.gui.SpriteToolbar;
19 | import vulc.luag.editor.sprite.history.History;
20 | import vulc.luag.editor.sprite.tool.SpriteToolkit;
21 | import vulc.luag.game.Game;
22 | import vulc.luag.gfx.gui.GUIComponent;
23 | import vulc.luag.gfx.gui.GUIPanel;
24 | import vulc.luag.gfx.gui.GUITextBox;
25 | import vulc.luag.gfx.panel.EditorPanel;
26 | import vulc.luag.input.InputHandler.Key;
27 | import vulc.luag.input.InputHandler.KeyType;
28 |
29 | public class SpriteEditor extends Editor {
30 |
31 | public static final int PALETTE_SIZE = 8;
32 |
33 | public static final int DEFAULT_SCALE = 6;
34 |
35 | // preview and atlas
36 | public final SpriteAtlasPreview atlasPreview;
37 | public final Bitmap atlas;
38 | public Bitmap preview;
39 | public int spriteID = 0;
40 | public int scope = 1;
41 |
42 | public final SpriteToolkit toolkit = new SpriteToolkit();
43 | private final Key ctrl, p, f, k, s,
44 | z, y, c, v,
45 | up, left, down, right;
46 |
47 | // select color and last colors
48 | public int selectedColor;
49 | public final List lastColors = new ArrayList();
50 |
51 | // editing history
52 | public final History history = new History(this, 100);
53 | public boolean isEditing = false, wasEditing = false;
54 | public boolean shouldSaveContent = false;
55 |
56 | // selection and copy/paste
57 | public int selx0, sely0, selx1, sely1;
58 | public boolean pasteMode = false;
59 | public Bitmap copied;
60 | public int xPasted, yPasted;
61 |
62 | public GUITextBox selectColorTxt;
63 |
64 | public SpriteEditor(EditorPanel panel, int x, int y, int w, int h) {
65 | super(panel, x, y, w, h);
66 | this.atlas = panel.game.atlas;
67 |
68 | // keys
69 | this.ctrl = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_CONTROL);
70 | this.p = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_P);
71 | this.f = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_F);
72 | this.k = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_K);
73 | this.s = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_S);
74 |
75 | this.z = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_Z);
76 | this.y = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_Y);
77 | this.c = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_C);
78 | this.v = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_V);
79 |
80 | this.up = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_UP);
81 | this.left = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_LEFT);
82 | this.down = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_DOWN);
83 | this.right = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_RIGHT);
84 |
85 | preview = panel.game.getSprite(spriteID, scope, scope);
86 |
87 | // default palette
88 | lastColors.add(0x00_00_00);
89 | lastColors.add(0xff_ff_ff);
90 | lastColors.add(0xff_00_00);
91 | lastColors.add(0x00_ff_00);
92 | lastColors.add(0x00_00_ff);
93 | lastColors.add(0xff_ff_00);
94 | lastColors.add(0xff_00_ff);
95 | lastColors.add(0x00_ff_ff);
96 |
97 | history.save();
98 |
99 | // INTERFACE
100 | guiPanel.background = 0x000000;
101 |
102 | int previewSize = Game.SPR_SIZE * DEFAULT_SCALE;
103 | GUIComponent sprPreview = new SpritePreview((guiPanel.w - previewSize) / 2 - SpritePreview.BORDER, 5,
104 | previewSize + SpritePreview.BORDER * 2,
105 | previewSize + SpritePreview.BORDER * 2,
106 | this);
107 | guiPanel.add(sprPreview);
108 |
109 | int scopes[] = {1, 2};
110 | SpriteScopeSelector scopeSelector = new SpriteScopeSelector(sprPreview.x - 9 - 5,
111 | (sprPreview.y + sprPreview.h) / 2 - 5,
112 | 10, 1 + scopes.length * 9,
113 | this, scopes);
114 | guiPanel.add(scopeSelector);
115 |
116 | int hAtlas = 8 * Game.SPR_SIZE;
117 | atlasPreview = new SpriteAtlasPreview((guiPanel.w - atlas.width) / 2, guiPanel.h - hAtlas - 5,
118 | atlas.width, hAtlas,
119 | this);
120 | guiPanel.add(atlasPreview);
121 |
122 | int hToolbar = 9 * 5 + 1;
123 | GUIPanel toolbar = new SpriteToolbar(atlasPreview.x, sprPreview.y + (sprPreview.h - hToolbar) / 2,
124 | 19, hToolbar,
125 | this);
126 | guiPanel.add(toolbar);
127 |
128 | int xColorbar = sprPreview.x + sprPreview.w + 5;
129 | GUIPanel colorbar = new SpriteColorbar(xColorbar, 5,
130 | guiPanel.w - xColorbar - 5, sprPreview.h,
131 | this);
132 | guiPanel.add(colorbar);
133 |
134 | toolkit.setTool(toolkit.pencil);
135 | selectColor(0xffffff);
136 | }
137 |
138 | public void tick() {
139 | if(ctrl.isKeyDown()) {
140 | if(z.isPressed()) undo();
141 | if(y.isPressed()) redo();
142 |
143 | if(c.isPressed() && toolkit.currentTool == toolkit.select) copy();
144 | if(v.isPressed()) paste();
145 | } else {
146 | if(p.isPressed()) toolkit.setTool(toolkit.pencil);
147 | if(f.isPressed()) toolkit.setTool(toolkit.bucket);
148 | if(k.isPressed()) toolkit.setTool(toolkit.pickup);
149 | if(s.isPressed()) toolkit.setTool(toolkit.select);
150 |
151 | if(up.isPressed()) moveSelected(0, -1);
152 | if(left.isPressed()) moveSelected(-1, 0);
153 | if(down.isPressed()) moveSelected(0, +1);
154 | if(right.isPressed()) moveSelected(+1, 0);
155 | }
156 |
157 | if(pasteMode && toolkit.currentTool != toolkit.select) {
158 | endPaste();
159 | }
160 |
161 | boolean shouldSave = wasEditing && !isEditing;
162 | wasEditing = isEditing;
163 | isEditing = false;
164 |
165 | if(shouldSave) {
166 | saveHistory();
167 | }
168 | }
169 |
170 | public void updatePreview() {
171 | preview = atlasPreview.getPreview();
172 | }
173 |
174 | private void saveHistory() {
175 | // update atlas and then history.save will record it
176 | atlas.draw(preview, (spriteID % 16) * Game.SPR_SIZE, (spriteID / 16) * Game.SPR_SIZE);
177 | history.save();
178 | }
179 |
180 | public String getTitle() {
181 | return "Sprite Editor";
182 | }
183 |
184 | public void selectColor(int color) {
185 | if(!lastColors.contains(selectedColor)) {
186 | lastColors.add(0, selectedColor);
187 | lastColors.remove(PALETTE_SIZE);
188 | }
189 | this.selectedColor = color;
190 |
191 | String colorString = Integer.toString(color, 16);
192 | while(colorString.length() < 6) {
193 | colorString = "0" + colorString;
194 | }
195 | selectColorTxt.text = colorString;
196 | }
197 |
198 | public boolean shouldSave() {
199 | return shouldSaveContent;
200 | }
201 |
202 | public void onSave() {
203 | try {
204 | int[] pixels = new int[atlas.width * atlas.height];
205 | for(int i = 0; i < atlas.size(); i++) {
206 | pixels[i] = atlas.raster.getPixel(i);
207 | }
208 |
209 | BufferedImage img = new BufferedImage(atlas.width, atlas.height, BufferedImage.TYPE_INT_RGB);
210 | img.setRGB(0, 0, atlas.width, atlas.height, pixels, 0, atlas.width);
211 |
212 | ImageIO.write(img, "png", new File(Game.ATLAS_FILE));
213 | shouldSaveContent = false;
214 | } catch(IOException e) {
215 | e.printStackTrace();
216 | }
217 | }
218 |
219 | public void undo() {
220 | if(history.undo()) {
221 | updatePreview();
222 | shouldSaveContent = true;
223 | }
224 | }
225 |
226 | public void redo() {
227 | if(history.redo()) {
228 | updatePreview();
229 | shouldSaveContent = true;
230 | }
231 | }
232 |
233 | public void copy() {
234 | fixCopySelection();
235 | copied = preview.getSubimage(selx0, sely0, selx1 - selx0 + 1, sely1 - sely0 + 1);
236 | }
237 |
238 | public void paste() {
239 | if(copied == null) return;
240 | if(pasteMode) endPaste();
241 |
242 | pasteMode = true;
243 | toolkit.setTool(toolkit.select);
244 | xPasted = 0;
245 | yPasted = 0;
246 |
247 | selx0 = xPasted;
248 | sely0 = yPasted;
249 | selx1 = xPasted + copied.width - 1;
250 | sely1 = yPasted + copied.height - 1;
251 | }
252 |
253 | public void endPaste() {
254 | if(!pasteMode) return;
255 |
256 | pasteMode = false;
257 | preview.draw(copied, xPasted, yPasted);
258 |
259 | saveHistory();
260 | shouldSaveContent = true;
261 | }
262 |
263 | public void moveSelected(int x, int y) {
264 | if(pasteMode) {
265 | xPasted += x;
266 | yPasted += y;
267 |
268 | selx0 += x;
269 | sely0 += y;
270 | selx1 += x;
271 | sely1 += y;
272 | } else if(toolkit.currentTool == toolkit.select) {
273 | copy();
274 |
275 | pasteMode = true;
276 | xPasted = selx0;
277 | yPasted = sely0;
278 |
279 | // at this point, selection was already fixed, in copy()
280 | preview.fill(selx0, sely0, selx1, sely1, 0xff00ff);
281 |
282 | // after setting pasteMode it's necessary to move the pasted bitmap
283 | moveSelected(x, y);
284 | }
285 | }
286 |
287 | private void fixCopySelection() {
288 | if(selx0 < 0) selx0 = 0;
289 | if(sely0 < 0) sely0 = 0;
290 | if(selx1 < 0) selx1 = 0;
291 | if(sely1 < 0) sely1 = 0;
292 |
293 | if(selx0 >= preview.width) selx0 = preview.width - 1;
294 | if(sely0 >= preview.height) sely0 = preview.height - 1;
295 | if(selx1 >= preview.width) selx1 = preview.width - 1;
296 | if(sely1 >= preview.height) sely1 = preview.height - 1;
297 |
298 | int x0 = Math.min(selx0, selx1);
299 | int y0 = Math.min(sely0, sely1);
300 | int x1 = Math.max(selx0, selx1);
301 | int y1 = Math.max(sely0, sely1);
302 |
303 | selx0 = x0;
304 | sely0 = y0;
305 | selx1 = x1;
306 | sely1 = y1;
307 | }
308 |
309 | public void setScope(int scope) {
310 | this.scope = scope;
311 |
312 | atlasPreview.setScope(scope);
313 |
314 | updatePreview();
315 | }
316 |
317 | }
318 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteAtlasPreview.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.gui.AtlasPreview;
5 | import vulc.luag.editor.sprite.SpriteEditor;
6 | import vulc.luag.game.Game;
7 |
8 | public class SpriteAtlasPreview extends AtlasPreview {
9 |
10 | private final SpriteEditor editor;
11 |
12 | public SpriteAtlasPreview(int x, int y, int w, int h, SpriteEditor editor) {
13 | super(x, y, w, h, editor.editorPanel.game);
14 | this.editor = editor;
15 | }
16 |
17 | public Bitmap getPreview() {
18 | Game game = editor.editorPanel.game;
19 | return game.getSprite(selected, editor.scope, editor.scope);
20 | }
21 |
22 | public void setSelected(int xs, int ys) {
23 | super.setSelected(xs, ys);
24 |
25 | editor.endPaste();
26 |
27 | editor.spriteID = selected;
28 | editor.updatePreview();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteColorbar.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.gfx.Colors;
5 | import vulc.luag.gfx.Screen;
6 | import vulc.luag.gfx.gui.GUIComponent;
7 | import vulc.luag.gfx.gui.GUIPanel;
8 | import vulc.luag.gfx.gui.GUITextBox;
9 |
10 | public class SpriteColorbar extends GUIPanel {
11 |
12 | public SpriteColorbar(int x, int y, int w, int h, SpriteEditor editor) {
13 | super(x, y, w, h);
14 |
15 | this.background = Colors.BACKGROUND_0;
16 |
17 | GUIComponent colorPreview = new GUIComponent((w - 16) / 2, 1, 16, 16) {
18 | public void render(Screen screen) {
19 | screen.fill(x, y, x + w - 1, y + h - 1, editor.selectedColor);
20 | }
21 | };
22 | this.add(colorPreview);
23 |
24 | GUITextBox selectColorTxt = new GUITextBox(1, 18, w - 2, 10) {
25 | public void onEnterPress() {
26 | super.onEnterPress();
27 | editor.selectColor(Integer.parseInt(text, 16));
28 | }
29 | };
30 | selectColorTxt.opaque = true;
31 | selectColorTxt.background = 0xffffff;
32 | selectColorTxt.textColor = 0x000000;
33 | selectColorTxt.nChars = 6;
34 | selectColorTxt.acceptedText = GUITextBox.HEX_ONLY;
35 | editor.selectColorTxt = selectColorTxt;
36 | this.add(selectColorTxt);
37 |
38 | int historyColumns = 4;
39 | int hHistory = 9 * (SpriteEditor.PALETTE_SIZE / historyColumns) + 1;
40 | int wHistory = 9 * historyColumns + 1;
41 | GUIPanel history = new SpriteColorbarPalette((w - wHistory) / 2, h - hHistory - 1,
42 | wHistory, hHistory,
43 | editor, historyColumns);
44 | this.add(history);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteColorbarPalette.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.gfx.Colors;
5 | import vulc.luag.gfx.Screen;
6 | import vulc.luag.gfx.gui.GUIComponent;
7 | import vulc.luag.gfx.gui.GUIPanel;
8 |
9 | public class SpriteColorbarPalette extends GUIPanel {
10 |
11 | public SpriteColorbarPalette(int x, int y, int w, int h, SpriteEditor editor, int columns) {
12 | super(x, y, w, h);
13 |
14 | this.background = Colors.BACKGROUND_1;
15 |
16 | for(int i = 0; i < SpriteEditor.PALETTE_SIZE; i++) {
17 | int id = i;
18 | int xt = (id % columns);
19 | int yt = (id / columns);
20 |
21 | GUIComponent comp = new GUIComponent(1 + xt * 9, 1 + yt * 9, 8, 8) {
22 | public void render(Screen screen) {
23 | screen.fill(x, y, x + w - 1, y + h - 1, editor.lastColors.get(id));
24 | }
25 |
26 | public void onMousePress(int xMouse, int yMouse) {
27 | editor.selectColor(editor.lastColors.get(id));
28 | }
29 | };
30 | this.add(comp);
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpritePreview.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 | import vulc.luag.editor.sprite.tool.SpriteTool;
6 | import vulc.luag.editor.sprite.tool.SpriteToolkit;
7 | import vulc.luag.gfx.Colors;
8 | import vulc.luag.gfx.Screen;
9 | import vulc.luag.gfx.gui.GUIComponent;
10 |
11 | public class SpritePreview extends GUIComponent {
12 |
13 | private enum ToolAction {
14 | DOWN, PRESS, RELEASE
15 | }
16 |
17 | public static final int BORDER = 2;
18 |
19 | public final SpriteEditor editor;
20 | private int animationTicks = 0;
21 |
22 | public SpritePreview(int x, int y, int w, int h, SpriteEditor editor) {
23 | super(x, y, w, h);
24 | this.editor = editor;
25 |
26 | this.opaque = true;
27 | this.background = Colors.BACKGROUND_0;
28 | }
29 |
30 | public void tick() {
31 | animationTicks++;
32 | }
33 |
34 | public void render(Screen screen) {
35 | super.render(screen);
36 | Bitmap preview = editor.preview.getCopy();
37 |
38 | if(editor.pasteMode) {
39 | preview.draw(editor.copied, editor.xPasted, editor.yPasted);
40 | }
41 |
42 | // selection highlight
43 | SpriteToolkit toolkit = editor.toolkit;
44 | if(toolkit.currentTool == toolkit.select) {
45 | int x0 = Math.min(editor.selx0, editor.selx1);
46 | int y0 = Math.min(editor.sely0, editor.sely1);
47 | int x1 = Math.max(editor.selx0, editor.selx1);
48 | int y1 = Math.max(editor.sely0, editor.sely1);
49 |
50 | int transparency = animationTicks / 50 % 2 == 0 ? 0x55 : 0x77;
51 | preview.fill(x0, y0, x1, y1, 0xffffff, transparency);
52 | }
53 |
54 | preview = preview.getScaled(SpriteEditor.DEFAULT_SCALE / editor.scope);
55 | screen.draw(preview, x + BORDER, y + BORDER);
56 |
57 | }
58 |
59 | public void onMouseDown(int xMouse, int yMouse) {
60 | onAction(xMouse, yMouse, ToolAction.DOWN);
61 | }
62 |
63 | public void onMousePress(int xMouse, int yMouse) {
64 | onAction(xMouse, yMouse, ToolAction.PRESS);
65 | }
66 |
67 | public void onMouseRelease(int xMouse, int yMouse) {
68 | onAction(xMouse, yMouse, ToolAction.RELEASE);
69 | }
70 |
71 | private void onAction(int xMouse, int yMouse, ToolAction action) {
72 | int scale = SpriteEditor.DEFAULT_SCALE / editor.scope;
73 |
74 | int xPix = Math.floorDiv(xMouse - BORDER, scale);
75 | int yPix = Math.floorDiv(yMouse - BORDER, scale);
76 |
77 | if(xPix < 0 || xPix >= editor.preview.width
78 | || yPix < 0 || yPix >= editor.preview.height) return;
79 |
80 | SpriteTool tool = editor.toolkit.currentTool;
81 |
82 | if((action == ToolAction.DOWN && tool.onMouseDown(xPix, yPix, editor, editor.preview))
83 | || (action == ToolAction.PRESS && tool.onMousePress(xPix, yPix, editor, editor.preview))
84 | || (action == ToolAction.RELEASE && tool.onMouseRelease(xPix, yPix, editor, editor.preview))) {
85 | editor.isEditing = true;
86 | editor.shouldSaveContent = true;
87 | } else if(editor.wasEditing) {
88 | editor.isEditing = true;
89 | }
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteScopeButton.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.gfx.Colors;
5 | import vulc.luag.gfx.Icons;
6 | import vulc.luag.gfx.gui.GUIButton;
7 |
8 | public class SpriteScopeButton extends GUIButton {
9 |
10 | public SpriteScopeButton(int x, int y, int w, int h, SpriteEditor editor, int scope) {
11 | super(x, y, w, h);
12 | background = Colors.BACKGROUND_1;
13 | colorAsBool = Colors.FOREGROUND_1;
14 | opaque = true;
15 |
16 | if(scope == 1) {
17 | boolImage = Icons.SPRITE_SCOPE_1;
18 | } else if(scope == 2) {
19 | boolImage = Icons.SPRITE_SCOPE_2;
20 | }
21 |
22 | this.onMousePressAction = () -> {
23 | if(editor.scope != scope) {
24 | editor.setScope(scope);
25 | }
26 | };
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteScopeSelector.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.gfx.Colors;
5 | import vulc.luag.gfx.gui.GUIPanel;
6 |
7 | public class SpriteScopeSelector extends GUIPanel {
8 |
9 | public SpriteScopeSelector(int x, int y, int w, int h, SpriteEditor editor, int[] scopes) {
10 | super(x, y, w, h);
11 | background = Colors.BACKGROUND_0;
12 |
13 | for(int i = 0; i < scopes.length; i++) {
14 | add(new SpriteScopeButton(1, 1 + i * 9, 8, 8, editor, scopes[i]));
15 | }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteToolButton.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.editor.sprite.tool.SpriteTool;
5 | import vulc.luag.editor.sprite.tool.SpriteToolkit;
6 | import vulc.luag.gfx.gui.GUIButton;
7 |
8 | public class SpriteToolButton extends GUIButton {
9 |
10 | public final SpriteTool tool;
11 |
12 | public SpriteToolButton(int x, int y, int w, int h, SpriteEditor editor, SpriteTool tool) {
13 | super(x, y, w, h);
14 |
15 | this.tool = tool;
16 |
17 | SpriteToolkit toolkit = editor.toolkit;
18 | toolkit.buttons.add(this);
19 |
20 | this.onMousePressAction = () -> {
21 | toolkit.setTool(tool);
22 | };
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/gui/SpriteToolbar.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.gui;
2 |
3 | import vulc.luag.editor.sprite.SpriteEditor;
4 | import vulc.luag.editor.sprite.tool.SpriteTool;
5 | import vulc.luag.editor.sprite.tool.SpriteToolkit;
6 | import vulc.luag.gfx.Colors;
7 | import vulc.luag.gfx.Icons;
8 | import vulc.luag.gfx.gui.GUIButton;
9 | import vulc.luag.gfx.gui.GUIPanel;
10 |
11 | public class SpriteToolbar extends GUIPanel {
12 |
13 | public SpriteToolbar(int x, int y, int w, int h, SpriteEditor editor) {
14 | super(x, y, w, h);
15 |
16 | this.background = Colors.BACKGROUND_0;
17 |
18 | SpriteToolkit toolkit = editor.toolkit;
19 |
20 | SpriteToolButton pencilButton = createToolButton(0, 0, editor, toolkit.pencil);
21 | pencilButton.setImage(Icons.PENCIL_TOOL, Colors.FOREGROUND_1);
22 | this.add(pencilButton);
23 |
24 | SpriteToolButton bucketButton = createToolButton(0, 1, editor, toolkit.bucket);
25 | bucketButton.setImage(Icons.BUCKET_TOOL, Colors.FOREGROUND_1);
26 | this.add(bucketButton);
27 |
28 | SpriteToolButton pickupButton = createToolButton(0, 2, editor, toolkit.pickup);
29 | pickupButton.setImage(Icons.PICKUP_TOOL, Colors.FOREGROUND_1);
30 | this.add(pickupButton);
31 |
32 | GUIButton undoButton = createGUIButton(0, 3);
33 | undoButton.setImage(Icons.UNDO, Colors.FOREGROUND_1);
34 | undoButton.onMousePressAction = () -> {
35 | editor.undo();
36 | };
37 | this.add(undoButton);
38 |
39 | GUIButton redoButton = createGUIButton(0, 4);
40 | redoButton.setImage(Icons.REDO, Colors.FOREGROUND_1);
41 | redoButton.onMousePressAction = () -> {
42 | editor.redo();
43 | };
44 | this.add(redoButton);
45 |
46 | SpriteToolButton selectButton = createToolButton(1, 0, editor, toolkit.select);
47 | selectButton.setImage(Icons.SELECT_TOOL, Colors.FOREGROUND_1);
48 | this.add(selectButton);
49 | }
50 |
51 | private static SpriteToolButton createToolButton(int x, int y, SpriteEditor editor, SpriteTool tool) {
52 | int[] b = getButtonBounds(x, y);
53 | return (SpriteToolButton) setAttributes(new SpriteToolButton(b[0], b[1], b[2], b[3], editor, tool));
54 | }
55 |
56 | private static GUIButton createGUIButton(int x, int y) {
57 | int[] b = getButtonBounds(x, y);
58 | return setAttributes(new GUIButton(b[0], b[1], b[2], b[3]));
59 | }
60 |
61 | private static int[] getButtonBounds(int x, int y) {
62 | int[] result = new int[4];
63 | result[0] = 1 + 9 * x;
64 | result[1] = 1 + 9 * y;
65 | result[2] = 8;
66 | result[3] = 8;
67 | return result;
68 | }
69 |
70 | private static GUIButton setAttributes(GUIButton button) {
71 | button.opaque = true;
72 | button.background = Colors.BACKGROUND_1;
73 | return button;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/history/History.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.history;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import vulc.bitmap.Bitmap;
7 | import vulc.luag.editor.sprite.SpriteEditor;
8 |
9 | public class History {
10 |
11 | private final SpriteEditor editor;
12 | private final int historySize;
13 |
14 | private List> records = new ArrayList>();
15 | private int nextHistoryIndex = 0;
16 |
17 | public History(SpriteEditor editor, int size) {
18 | this.editor = editor;
19 | this.historySize = size;
20 | }
21 |
22 | public void save() {
23 | // if UNDOs where done, clear the "future" records
24 | records = records.subList(0, nextHistoryIndex);
25 |
26 | records.add(editor.atlas.getCopy());
27 | if(records.size() > historySize) {
28 | records.remove(0);
29 | }
30 | nextHistoryIndex = records.size();
31 | }
32 |
33 | public boolean undo() {
34 | if(nextHistoryIndex == 1) return false;
35 |
36 | editor.atlas.draw(records.get(nextHistoryIndex - 2), 0, 0);
37 | nextHistoryIndex--;
38 |
39 | return true;
40 | }
41 |
42 | public boolean redo() {
43 | if(nextHistoryIndex == records.size()) return false;
44 |
45 | editor.atlas.draw(records.get(nextHistoryIndex), 0, 0);
46 | nextHistoryIndex++;
47 |
48 | return true;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/BucketTool.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 |
6 | public class BucketTool extends SpriteTool {
7 |
8 | public boolean onMouseDown(int x, int y, SpriteEditor editor, Bitmap canvas) {
9 | boolean[][] checked = new boolean[canvas.width][canvas.height];
10 |
11 | int newColor = editor.selectedColor;
12 | int backgroundColor = canvas.getPixel(x, y);
13 |
14 | if(newColor == backgroundColor) return false;
15 |
16 | fill(x, y, canvas, backgroundColor, newColor, checked);
17 | return true;
18 | }
19 |
20 | private void fill(int x, int y, Bitmap canvas, int backgroundColor, int newColor, boolean[][] checked) {
21 | if(x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) return;
22 | if(checked[x][y]) return;
23 |
24 | checked[x][y] = true;
25 | if(canvas.getPixel(x, y) == backgroundColor) {
26 | canvas.setPixel(x, y, newColor);
27 |
28 | fill(x - 1, y, canvas, backgroundColor, newColor, checked);
29 | fill(x + 1, y, canvas, backgroundColor, newColor, checked);
30 | fill(x, y - 1, canvas, backgroundColor, newColor, checked);
31 | fill(x, y + 1, canvas, backgroundColor, newColor, checked);
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/PencilTool.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 |
6 | public class PencilTool extends SpriteTool {
7 |
8 | public boolean onMouseDown(int x, int y, SpriteEditor editor, Bitmap canvas) {
9 | int color = editor.selectedColor;
10 | if(canvas.getPixel(x, y) != color) {
11 | canvas.setPixel(x, y, color);
12 | return true;
13 | }
14 | return false;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/PickupTool.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 |
6 | public class PickupTool extends SpriteTool {
7 |
8 | public boolean onMouseDown(int x, int y, SpriteEditor editor, Bitmap canvas) {
9 | editor.selectColor(canvas.getPixel(x, y));
10 |
11 | SpriteToolkit toolkit = editor.toolkit;
12 | toolkit.setTool(toolkit.pencil);
13 |
14 | return false;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/SelectTool.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 |
6 | public class SelectTool extends SpriteTool {
7 |
8 | public boolean onMousePress(int x, int y, SpriteEditor editor, Bitmap canvas) {
9 | editor.selx0 = x;
10 | editor.sely0 = y;
11 |
12 | if(editor.pasteMode) editor.endPaste();
13 | return false;
14 | }
15 |
16 | public boolean onMouseDown(int x, int y, SpriteEditor editor, Bitmap canvas) {
17 | editor.selx1 = x;
18 | editor.sely1 = y;
19 |
20 | if(editor.pasteMode) editor.endPaste();
21 | return false;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/SpriteTool.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.editor.sprite.SpriteEditor;
5 |
6 | public abstract class SpriteTool {
7 |
8 | // returns true if is editing
9 | public boolean onMouseDown(int x, int y, SpriteEditor editor, Bitmap canvas) {
10 | return false;
11 | }
12 |
13 | public boolean onMousePress(int x, int y, SpriteEditor editor, Bitmap canvas) {
14 | return false;
15 | }
16 |
17 | public boolean onMouseRelease(int x, int y, SpriteEditor editor, Bitmap canvas) {
18 | return false;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/vulc/luag/editor/sprite/tool/SpriteToolkit.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.editor.sprite.tool;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import vulc.luag.editor.sprite.gui.SpriteToolButton;
7 | import vulc.luag.gfx.Colors;
8 |
9 | public class SpriteToolkit {
10 |
11 | public final List buttons = new ArrayList();
12 |
13 | public final SpriteTool pencil = new PencilTool();
14 | public final SpriteTool bucket = new BucketTool();
15 | public final SpriteTool pickup = new PickupTool();
16 | public final SpriteTool select = new SelectTool();
17 |
18 | public SpriteTool currentTool;
19 |
20 | public void setTool(SpriteTool tool) {
21 | currentTool = tool;
22 |
23 | for(int i = 0; i < buttons.size(); i++) {
24 | SpriteToolButton button = buttons.get(i);
25 |
26 | if(button.tool == tool) {
27 | button.colorAsBool = Colors.FOREGROUND_HIGHLIGHT;
28 | } else {
29 | button.colorAsBool = Colors.FOREGROUND_1;
30 | }
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/Game.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game;
2 |
3 | import java.awt.event.KeyEvent;
4 | import java.awt.image.BufferedImage;
5 | import java.io.BufferedInputStream;
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 | import java.nio.file.NoSuchFileException;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.zip.ZipEntry;
16 | import java.util.zip.ZipFile;
17 | import java.util.zip.ZipInputStream;
18 |
19 | import javax.imageio.ImageIO;
20 | import javax.swing.KeyStroke;
21 |
22 | import com.google.gson.JsonArray;
23 | import com.google.gson.JsonElement;
24 | import com.google.gson.JsonObject;
25 | import com.google.gson.JsonParseException;
26 | import com.google.gson.JsonParser;
27 |
28 | import vulc.bitmap.Bitmap;
29 | import vulc.bitmap.IntBitmap;
30 | import vulc.luag.Console;
31 | import vulc.luag.Console.Mode;
32 | import vulc.luag.editor.map.MapCompiler;
33 | import vulc.luag.game.map.Map;
34 | import vulc.luag.game.save.SaveSystem;
35 | import vulc.luag.gfx.panel.GamePanel;
36 | import vulc.luag.gfx.panel.ShellPanel;
37 | import vulc.luag.input.InputHandler;
38 | import vulc.luag.input.InputHandler.Key;
39 | import vulc.luag.input.InputHandler.KeyType;
40 |
41 | public class Game {
42 |
43 | public static final String USERDATA_DIR_NAME = "console-userdata";
44 | public static final String SCRIPT_DIR_NAME = "script";
45 | public static final String SFX_DIR_NAME = "sfx";
46 | public static final String CONFIG_FILE_NAME = "config.json";
47 | public static final String ATLAS_FILE_NAME = "atlas.png";
48 | public static final String MAP_FILE_NAME = "map";
49 | public static final String CARTRIDGE_INFO_NAME = ".cartridge-info";
50 |
51 | public static final String USERDATA_DIR = Console.rootDirectory + USERDATA_DIR_NAME;
52 | public static final String SCRIPT_DIR = USERDATA_DIR + "/" + SCRIPT_DIR_NAME;
53 | public static final String SFX_DIR = USERDATA_DIR + "/" + SFX_DIR_NAME;
54 | public static final String CONFIG_FILE = USERDATA_DIR + "/" + CONFIG_FILE_NAME;
55 | public static final String ATLAS_FILE = USERDATA_DIR + "/" + ATLAS_FILE_NAME;
56 | public static final String MAP_FILE = USERDATA_DIR + "/" + MAP_FILE_NAME;
57 |
58 | public static final int SPR_SIZE = 8;
59 |
60 | private final LuaScriptCore scriptCore = new LuaScriptCore();
61 | private final InputHandler input = new InputHandler();
62 | public final GameSounds sounds = new GameSounds();
63 |
64 | public JsonObject jsonConfig, cartridgeInfo;
65 | public SaveSystem saveSystem;
66 | public Bitmap atlas;
67 | public Map map;
68 |
69 | public ZipFile cartridgeFile;
70 |
71 | public final List keys = new ArrayList();
72 |
73 | private Key debugRestartGame = null;
74 | private Key debugGotoShell = null;
75 |
76 | public Game() {
77 | if(Console.mode == Mode.DEVELOPER) {
78 | debugRestartGame = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_F7);
79 | debugGotoShell = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_F8);
80 | }
81 | }
82 |
83 | // init resources in console-userdata
84 | public boolean initDevResources() {
85 | Console.LOGGER.info("Loading '" + USERDATA_DIR_NAME + "' resources...");
86 | saveSystem = new SaveSystem(USERDATA_DIR);
87 |
88 | // root
89 | File rootFolder = new File(USERDATA_DIR);
90 | if(!rootFolder.isDirectory()) {
91 | Console.die("Error:\n"
92 | + "'" + USERDATA_DIR_NAME + "'\n"
93 | + "folder not found");
94 | return false;
95 | }
96 |
97 | // sounds
98 | Console.LOGGER.info("Load '" + SFX_DIR_NAME + "'");
99 | if(!sounds.init()) return false;
100 |
101 | // config.json
102 | Console.LOGGER.info("Load '" + CONFIG_FILE_NAME + "'");
103 | try(InputStream in = new BufferedInputStream(new FileInputStream(CONFIG_FILE))) {
104 | if(!loadConfig(in)) return false;
105 | } catch(FileNotFoundException e) {
106 | Console.die("Error:\n"
107 | + "'" + Game.CONFIG_FILE_NAME + "'\n"
108 | + "file not found");
109 | return false;
110 | } catch(IOException e) {
111 | e.printStackTrace();
112 | }
113 |
114 | // atlas.png
115 | Console.LOGGER.info("Load '" + ATLAS_FILE_NAME + "'");
116 | try(InputStream in = new BufferedInputStream(new FileInputStream(ATLAS_FILE))) {
117 | if(!loadAtlas(in)) return false;
118 | } catch(FileNotFoundException e) {
119 | Console.die("Error:\n"
120 | + "'" + Game.ATLAS_FILE_NAME + "'\n"
121 | + "file not found");
122 | return false;
123 | } catch(IOException e) {
124 | e.printStackTrace();
125 | }
126 |
127 | // map
128 | Console.LOGGER.info("Load '" + MAP_FILE_NAME + "'");
129 | File mapFile = new File(MAP_FILE);
130 | try {
131 | map = Map.load(new BufferedInputStream(new FileInputStream(mapFile)));
132 | if(map == null) return false;
133 | } catch(FileNotFoundException e) {
134 | Console.LOGGER.info("Missing map file: generating new file");
135 |
136 | map = new Map(10, 10);
137 | MapCompiler.compile(map);
138 | }
139 | return true;
140 | }
141 |
142 | public boolean initCartridgeResources() {
143 | try {
144 | String cartridge = Console.cartridge;
145 | Console.LOGGER.info("Loading cartridge '" + cartridge + "' resources...");
146 | saveSystem = new SaveSystem(cartridge);
147 |
148 | try {
149 | cartridgeFile = new ZipFile(cartridge);
150 | } catch(FileNotFoundException | NoSuchFileException e) {
151 | Console.die("Error:\n"
152 | + "'" + cartridge + "'\n"
153 | + "cartridge not found");
154 | return false;
155 | }
156 | List entries = new ArrayList();
157 | {
158 | ZipInputStream zipIn = new ZipInputStream(new BufferedInputStream(new FileInputStream(cartridge)));
159 | while(true) {
160 | ZipEntry entry = zipIn.getNextEntry();
161 | if(entry != null) {
162 | entries.add(entry);
163 | } else {
164 | break;
165 | }
166 | }
167 | zipIn.close();
168 | }
169 |
170 | // sound
171 | Console.LOGGER.info("Load '" + SFX_DIR_NAME + "'");
172 | if(!sounds.initAsCartridge(cartridgeFile, entries)) return false;
173 |
174 | // config.json
175 | Console.LOGGER.info("Load '" + CONFIG_FILE_NAME + "'");
176 | ZipEntry configEntry = cartridgeFile.getEntry(CONFIG_FILE_NAME);
177 | if(configEntry == null) {
178 | Console.die("Cartridge Error:\n"
179 | + "'" + CONFIG_FILE_NAME + "'\n"
180 | + "file not found");
181 | return false;
182 | } else {
183 | if(!loadConfig(cartridgeFile.getInputStream(configEntry))) {
184 | return false;
185 | }
186 | }
187 |
188 | // atlas.png
189 | Console.LOGGER.info("Load '" + ATLAS_FILE_NAME + "'");
190 | ZipEntry atlasEntry = cartridgeFile.getEntry(ATLAS_FILE_NAME);
191 | if(atlasEntry == null) {
192 | Console.die("Cartridge Error:\n"
193 | + "'" + ATLAS_FILE_NAME + "'\n"
194 | + "file not found");
195 | return false;
196 | } else {
197 | if(!loadAtlas(cartridgeFile.getInputStream(atlasEntry))) {
198 | return false;
199 | }
200 | }
201 |
202 | // map
203 | Console.LOGGER.info("Load '" + MAP_FILE_NAME + "'");
204 | ZipEntry mapEntry = cartridgeFile.getEntry(MAP_FILE_NAME);
205 | if(mapEntry == null) {
206 | Console.die("Cartridge Error:\n"
207 | + "'" + MAP_FILE_NAME + "'\n"
208 | + "file not found");
209 | return false;
210 | } else {
211 | this.map = Map.load(cartridgeFile.getInputStream(mapEntry));
212 | if(map == null) return false;
213 | }
214 |
215 | // .cartridge-info
216 | Console.LOGGER.info("Load '" + CARTRIDGE_INFO_NAME + "'");
217 | ZipEntry cartridgeInfoEntry = cartridgeFile.getEntry(CARTRIDGE_INFO_NAME);
218 | if(cartridgeInfoEntry == null) {
219 | Console.die("Cartridge Error:\n"
220 | + "'" + CARTRIDGE_INFO_NAME + "'\n"
221 | + "file not found");
222 | return false;
223 | } else {
224 | if(!loadCartridgeInfo(cartridgeFile.getInputStream(cartridgeInfoEntry))) {
225 | return false;
226 | }
227 | }
228 | } catch(Exception e) {
229 | e.printStackTrace();
230 | return false;
231 | }
232 | return true;
233 | }
234 |
235 | public boolean initScript() {
236 | Console.LOGGER.info("Loading scripts");
237 |
238 | JsonElement keysElement = jsonConfig.get("keys");
239 | if(keysElement == null || !keysElement.isJsonArray()) {
240 | Console.die("Error:\n"
241 | + "'" + CONFIG_FILE_NAME + "'\n"
242 | + "must contain\n"
243 | + "a string array 'keys'");
244 | return false;
245 | }
246 |
247 | JsonArray keyArray = keysElement.getAsJsonArray();
248 | for(int i = 0; i < keyArray.size(); i++) {
249 | try {
250 | String key = keyArray.get(i).getAsString().toUpperCase();
251 | keys.add(input.new Key(KeyType.KEYBOARD,
252 | KeyStroke.getKeyStroke(key).getKeyCode()));
253 | } catch(Exception e) {
254 | Console.die("Error:\n"
255 | + "'" + CONFIG_FILE_NAME + "'\n"
256 | + "contains invalid keys");
257 | return false;
258 | }
259 | }
260 |
261 | input.init();
262 | if(scriptCore.init(this)) {
263 | Console.LOGGER.info("Game Started");
264 | }
265 | return true;
266 | }
267 |
268 | private boolean loadConfig(InputStream in) {
269 | jsonConfig = loadJson(in);
270 | if(jsonConfig == null) {
271 | Console.die("Error:\n"
272 | + "'" + Game.CONFIG_FILE_NAME + "'\n"
273 | + "must be a json object");
274 | return false;
275 | }
276 | return true;
277 | }
278 |
279 | private boolean loadCartridgeInfo(InputStream in) {
280 | cartridgeInfo = loadJson(in);
281 | if(cartridgeInfo == null) {
282 | Console.die("Error:\n"
283 | + "'" + Game.CARTRIDGE_INFO_NAME + "'\n"
284 | + "is invalid");
285 | return false;
286 | }
287 | return true;
288 | }
289 |
290 | private boolean loadAtlas(InputStream in) {
291 | try {
292 | BufferedImage img = ImageIO.read(in);
293 | if(img == null) {
294 | Console.die("Error:\n"
295 | + "'" + Game.ATLAS_FILE_NAME + "'\n"
296 | + "is not an image");
297 | return false;
298 | }
299 | atlas = new IntBitmap(img);
300 | if(atlas.width != 128 || atlas.height != 128) {
301 | Console.die("Error:\n"
302 | + "atlas must be\n"
303 | + "128x128 pixels\n"
304 | + "(256 sprites)");
305 | return false;
306 | }
307 | } catch(IOException e) {
308 | e.printStackTrace();
309 | }
310 | return true;
311 | }
312 |
313 | private JsonObject loadJson(InputStream in) {
314 | try {
315 | JsonElement element = new JsonParser().parse(new InputStreamReader(in));
316 | if(!element.isJsonObject()) return null;
317 | return element.getAsJsonObject();
318 | } catch(JsonParseException e) {
319 | return null;
320 | }
321 | }
322 |
323 | public void tick() {
324 | input.tick();
325 |
326 | scriptCore.tick();
327 | saveSystem.tick();
328 |
329 | if(Console.mode == Mode.DEVELOPER) {
330 | if(debugRestartGame.isPressed()) {
331 | Console.LOGGER.info("Restarting Game");
332 | Console.switchToPanel(new GamePanel());
333 | } else if(debugGotoShell.isPressed()) {
334 | Console.LOGGER.info("Stopping Game");
335 | Console.switchToPanel(new ShellPanel());
336 | }
337 | }
338 | }
339 |
340 | public void remove() {
341 | input.remove();
342 | sounds.remove();
343 |
344 | if(cartridgeFile != null) {
345 | try {
346 | cartridgeFile.close();
347 | } catch(IOException e) {
348 | e.printStackTrace();
349 | }
350 | cartridgeFile = null;
351 | }
352 | }
353 |
354 | public Bitmap getSprite(int id, int sw, int sh) {
355 | return getSprite(id % 16, id / 16, sw, sh);
356 | }
357 |
358 | public Bitmap getSprite(int x, int y, int sw, int sh) {
359 | return atlas.getSubimage(x * SPR_SIZE, y * SPR_SIZE, sw * SPR_SIZE, sh * SPR_SIZE);
360 | }
361 |
362 | }
363 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/GameSounds.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Set;
10 | import java.util.zip.ZipEntry;
11 | import java.util.zip.ZipFile;
12 |
13 | import vulc.luag.Console;
14 | import vulc.luag.sfx.Sound;
15 |
16 | public class GameSounds {
17 |
18 | private final HashMap list = new HashMap();
19 |
20 | public Sound get(String name) {
21 | return list.get(name);
22 | }
23 |
24 | public void remove() {
25 | Set keys = list.keySet();
26 | for(String key : keys) {
27 | list.get(key).onRemove();
28 | }
29 | list.clear();
30 | }
31 |
32 | public boolean init() {
33 | File sfxDir = new File(Game.SFX_DIR);
34 | if(!sfxDir.isDirectory()) {
35 | Console.die("Error:\n"
36 | + "'" + Game.SFX_DIR_NAME + "'\n"
37 | + "folder not found");
38 | return false;
39 | }
40 | readSoundsInFolder(sfxDir, "");
41 | return true;
42 | }
43 |
44 | private void readSoundsInFolder(File folder, String relativeToSfxRoot) {
45 | File[] files = folder.listFiles();
46 | for(File file : files) {
47 | String fileName = file.getName();
48 |
49 | if(file.isDirectory()) {
50 | readSoundsInFolder(file, relativeToSfxRoot + fileName + "/");
51 | } else {
52 | if(fileName.endsWith(".wav")) {
53 | String name = relativeToSfxRoot + fileName;
54 | name = name.substring(0, name.lastIndexOf('.'));
55 | try {
56 | list.put(name,
57 | new Sound(new BufferedInputStream(new FileInputStream(file))));
58 | } catch(IOException e) {
59 | e.printStackTrace();
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
66 | public boolean initAsCartridge(ZipFile zipFile, List entries) {
67 | for(ZipEntry entry : entries) {
68 | String fileName = entry.getName();
69 |
70 | if(!fileName.startsWith(Game.SFX_DIR_NAME)
71 | || !fileName.endsWith(".wav")) continue;
72 |
73 | String sfxName = fileName.substring(fileName.indexOf("/") + 1, fileName.lastIndexOf('.'));
74 | try {
75 | list.put(sfxName, new Sound(new BufferedInputStream(zipFile.getInputStream(entry))));
76 | } catch(IOException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | return true;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/LuaScriptCore.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.zip.ZipEntry;
9 |
10 | import org.luaj.vm2.Globals;
11 | import org.luaj.vm2.LoadState;
12 | import org.luaj.vm2.LuaError;
13 | import org.luaj.vm2.LuaFunction;
14 | import org.luaj.vm2.LuaValue;
15 | import org.luaj.vm2.compiler.LuaC;
16 | import org.luaj.vm2.lib.Bit32Lib;
17 | import org.luaj.vm2.lib.PackageLib;
18 | import org.luaj.vm2.lib.StringLib;
19 | import org.luaj.vm2.lib.TableLib;
20 | import org.luaj.vm2.lib.jse.JseBaseLib;
21 | import org.luaj.vm2.lib.jse.JseMathLib;
22 |
23 | import vulc.luag.Console;
24 | import vulc.luag.game.interfaces.LuaInterface;
25 |
26 | public class LuaScriptCore {
27 |
28 | private LuaFunction luaTick;
29 |
30 | // return true if init was successfully, else false
31 | public boolean init(Game game) {
32 | Globals globals = new Globals();
33 |
34 | // must load
35 | globals.load(new JseBaseLib());
36 | globals.load(new PackageLib());
37 |
38 | // math
39 | globals.load(new Bit32Lib());
40 | globals.load(new JseMathLib());
41 |
42 | // utils
43 | globals.load(new TableLib());
44 | globals.load(new StringLib());
45 |
46 | // disable require
47 | globals.set("require", LuaValue.NIL);
48 |
49 | /* libraries that are not loaded
50 | *
51 | * CoroutineLib
52 | * JseIoLib
53 | * JseOsLib
54 | * LuajavaLib
55 | */
56 |
57 | LoadState.install(globals);
58 | LuaC.install(globals);
59 |
60 | // load luag interface
61 | LuaInterface luaInterface;
62 | if(Console.cartridge != null) {
63 | String[] requestedVersion;
64 | int majorVerReq, minorVerReq;
65 | try {
66 | requestedVersion = game.cartridgeInfo.get("interface-version")
67 | .getAsString()
68 | .split("\\.");
69 |
70 | majorVerReq = Integer.parseInt(requestedVersion[0]);
71 | minorVerReq = Integer.parseInt(requestedVersion[1]);
72 | } catch(Exception e) {
73 | Console.die("Error:\n"
74 | + "'" + Game.CARTRIDGE_INFO_NAME + "'\n"
75 | + "is invalid");
76 | return false;
77 | }
78 |
79 | luaInterface = LuaInterface.getInterface(majorVerReq, game, globals);
80 | if(luaInterface == null) {
81 | Console.die("Error:\n"
82 | + "interface version " + majorVerReq + "\n"
83 | + "not supported");
84 | return false;
85 | }
86 | int yVer = LuaInterface.minorVersion(majorVerReq);
87 | if(yVer < minorVerReq) {
88 | Console.die("Error:\n"
89 | + "interface " + majorVerReq + "." + minorVerReq + "\n"
90 | + "not supported\n"
91 | + "Lastest: " + majorVerReq + "." + LuaInterface.minorVersion(majorVerReq));
92 | return false;
93 | }
94 | } else {
95 | luaInterface = LuaInterface.getInterface(LuaInterface.DEFAULT_MAJOR_VERSION, game, globals);
96 | }
97 | luaInterface.init();
98 |
99 | // READ main.lua
100 | boolean error = false;
101 | InputStream input = null;
102 | try {
103 | Console.LOGGER.info("Load 'main.lua'");
104 | if(Console.cartridge == null) {
105 | File mainFile = new File(Game.SCRIPT_DIR + "/main.lua");
106 | if(!mainFile.exists()) {
107 | Console.die("Error:\n"
108 | + "'" + Game.SCRIPT_DIR_NAME + "/main.lua'\n"
109 | + "file not found");
110 | return false;
111 | }
112 |
113 | input = new BufferedInputStream(new FileInputStream(mainFile));
114 | } else {
115 | ZipEntry mainLuaEntry = game.cartridgeFile.getEntry("script/main.lua");
116 | if(mainLuaEntry == null || mainLuaEntry.isDirectory()) {
117 | Console.die("Cartridge Error:\n"
118 | + "'" + Game.SCRIPT_DIR_NAME + "/main.lua'\n"
119 | + "file not found");
120 | return false;
121 | }
122 |
123 | input = game.cartridgeFile.getInputStream(mainLuaEntry);
124 | }
125 |
126 | globals.load(input, "@main.lua", "t", globals).call();
127 | } catch(LuaError e) {
128 | handleError(e);
129 | error = true;
130 | } catch(IOException e) {
131 | e.printStackTrace();
132 | error = true;
133 | }
134 |
135 | try {
136 | input.close();
137 | } catch(IOException e) {
138 | e.printStackTrace();
139 | }
140 | if(error) return false;
141 |
142 | try {
143 | // load tick
144 | LuaValue tick = globals.get("tick");
145 | if(tick == LuaValue.NIL || !tick.isfunction()) {
146 | Console.die("Error:\n"
147 | + "'main.lua' must contain\n"
148 | + "a function 'tick()'");
149 | return false;
150 | } else {
151 | luaTick = tick.checkfunction();
152 | }
153 |
154 | // call init
155 | Console.LOGGER.info("Calling 'init' function");
156 | LuaValue init = globals.get("init");
157 | if(init == LuaValue.NIL || !init.isfunction()) {
158 | Console.die("Error:\n"
159 | + "'main.lua' must contain\n"
160 | + "a function 'init()'");
161 | return false;
162 | } else {
163 | init.checkfunction().call();
164 | }
165 | } catch(LuaError e) {
166 | handleError(e);
167 | return false;
168 | }
169 | return true;
170 | }
171 |
172 | public void tick() {
173 | try {
174 | luaTick.call();
175 | } catch(LuaError e) {
176 | handleError(e);
177 | }
178 | }
179 |
180 | private void handleError(LuaError e) {
181 | String sep = "[\\\\/]";
182 |
183 | String msg = "LuaError: "
184 | + e.getLocalizedMessage()
185 | .replace("@", "")
186 | .replaceAll("\\.?" + sep + Game.USERDATA_DIR_NAME, "");
187 |
188 | Console.LOGGER.severe(msg);
189 |
190 | Console.die("Script Error:\n"
191 | + "see the log file");
192 | }
193 |
194 | }
195 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/cartridge/Cartridge.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game.cartridge;
2 |
3 | public abstract class Cartridge {
4 |
5 | public static final String EXTENSION = "luag";
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/interfaces/Interface001.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game.interfaces;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.zip.ZipEntry;
9 | import java.util.zip.ZipFile;
10 |
11 | import org.luaj.vm2.Globals;
12 | import org.luaj.vm2.LuaError;
13 | import org.luaj.vm2.LuaValue;
14 | import org.luaj.vm2.Varargs;
15 | import org.luaj.vm2.lib.OneArgFunction;
16 | import org.luaj.vm2.lib.ThreeArgFunction;
17 | import org.luaj.vm2.lib.TwoArgFunction;
18 | import org.luaj.vm2.lib.VarArgFunction;
19 |
20 | import vulc.luag.Console;
21 | import vulc.luag.game.Game;
22 | import vulc.luag.gfx.Screen;
23 | import vulc.luag.sfx.Sound;
24 |
25 | public class Interface001 extends LuaInterface {
26 |
27 | public Interface001(Game game, Globals env) {
28 | super(game, env);
29 | }
30 |
31 | public void init() {
32 | // SCREEN
33 | env.set("scr_w", Console.SCREEN.width);
34 | env.set("scr_h", Console.SCREEN.height);
35 |
36 | // FONT
37 | env.set("font_w", Screen.FONT.widthOf(' '));
38 | env.set("font_h", Screen.FONT.getHeight());
39 |
40 | // MAP
41 | env.set("map_w", game.map.width);
42 | env.set("map_h", game.map.height);
43 |
44 | // FUNCTIONS
45 | // general
46 | env.set("loadscript", new loadscript());
47 | env.set("log", new log());
48 |
49 | // keys
50 | env.set("key", new key());
51 | env.set("key_down", new key());
52 | env.set("key_pressed", new key_pressed());
53 | env.set("key_released", new key_released());
54 |
55 | // sound
56 | env.set("sfx", new sfx());
57 | env.set("sfx_play", new sfx());
58 | env.set("sfx_loop", new sfx_loop());
59 | env.set("sfx_stop", new sfx_stop());
60 |
61 | // screen
62 | env.set("settransparent", new settransparent());
63 | env.set("clear", new clear());
64 | env.set("pix", new pix());
65 | env.set("write", new write());
66 | env.set("spr", new spr());
67 |
68 | // map
69 | env.set("get_tile", new get_tile());
70 | env.set("set_tile", new set_tile());
71 | env.set("maprender", new maprender());
72 |
73 | // save
74 | env.set("save_data", new save_data());
75 | env.set("load_data", new load_data());
76 | }
77 |
78 | //---GENERAL---\\
79 |
80 | private class loadscript extends OneArgFunction {
81 | public LuaValue call(LuaValue script) {
82 | Console.LOGGER.info("Loading script '" + script + "'");
83 |
84 | InputStream input = null;
85 | try {
86 | if(Console.cartridge == null) {
87 | File file = new File(Game.SCRIPT_DIR + "/" + script);
88 | if(!file.exists()) throw new LuaError("bad argument: file '" + script + "' not found");
89 |
90 | input = new BufferedInputStream(new FileInputStream(file));
91 | } else {
92 | ZipFile cartridgeFile = game.cartridgeFile;
93 | ZipEntry entry = cartridgeFile.getEntry(Game.SCRIPT_DIR_NAME
94 | + "/" + script);
95 | if(entry == null) throw new LuaError("bad argument: file '" + script + "' not found");
96 |
97 | input = cartridgeFile.getInputStream(entry);
98 | }
99 | env.load(input, "@" + script, "t", env).call();
100 | } catch(IOException e) {
101 | e.printStackTrace();
102 | }
103 |
104 | try {
105 | input.close();
106 | } catch(IOException e) {
107 | e.printStackTrace();
108 | }
109 | return NIL;
110 | }
111 | }
112 |
113 | private class log extends OneArgFunction {
114 | public LuaValue call(LuaValue x) {
115 | Console.LOGGER.info(x.toString());
116 | return NIL;
117 | }
118 | }
119 |
120 | //---KEYS---\\
121 |
122 | private class key extends OneArgFunction {
123 | public LuaValue call(LuaValue id) {
124 | int key = id.checkint();
125 | if(key < 0 || key >= game.keys.size()) throw new LuaError("bad argument: key '" + key + "' does not exist");
126 |
127 | return valueOf(game.keys.get(key).isKeyDown());
128 | }
129 | }
130 |
131 | private class key_pressed extends OneArgFunction {
132 | public LuaValue call(LuaValue id) {
133 | int key = id.checkint();
134 | if(key < 0 || key >= game.keys.size()) throw new LuaError("bad argument: key '" + key + "' does not exist");
135 |
136 | return valueOf(game.keys.get(key).isPressed());
137 | }
138 | }
139 |
140 | private class key_released extends OneArgFunction {
141 | public LuaValue call(LuaValue id) {
142 | int key = id.checkint();
143 | if(key < 0 || key >= game.keys.size()) throw new LuaError("bad argument: key '" + key + "' does not exist");
144 |
145 | return valueOf(game.keys.get(key).isReleased());
146 | }
147 | }
148 |
149 | //---SOUND---\\
150 |
151 | private class sfx extends OneArgFunction {
152 | public LuaValue call(LuaValue name) {
153 | Sound sound = game.sounds.get(name.toString());
154 | if(sound == null) throw new LuaError("bad argument: sound '" + name + "' does not exist");
155 | sound.play();
156 |
157 | return NIL;
158 | }
159 | }
160 |
161 | private class sfx_loop extends OneArgFunction {
162 | public LuaValue call(LuaValue name) {
163 | Sound sound = game.sounds.get(name.toString());
164 | if(sound == null) throw new LuaError("bad argument: sound '" + name + "' does not exist");
165 | sound.loop();
166 |
167 | return NIL;
168 | }
169 | }
170 |
171 | private class sfx_stop extends OneArgFunction {
172 | public LuaValue call(LuaValue name) {
173 | Sound sound = game.sounds.get(name.toString());
174 | if(sound == null) throw new LuaError("bad argument: sound '" + name + "' does not exist");
175 | sound.stop();
176 |
177 | return NIL;
178 | }
179 | }
180 |
181 | //---SCREEN---\\
182 |
183 | private class settransparent extends OneArgFunction {
184 | public LuaValue call(LuaValue color) {
185 | Console.SCREEN.setTransparent(color.checkint());
186 | return NIL;
187 | }
188 | }
189 |
190 | private class clear extends OneArgFunction {
191 | public LuaValue call(LuaValue color) {
192 | Console.SCREEN.clear(color.checkint());
193 | return NIL;
194 | }
195 | }
196 |
197 | private class pix extends VarArgFunction {
198 | public Varargs invoke(Varargs args) {
199 | int x = args.arg(1).checkint();
200 | int y = args.arg(2).checkint();
201 | int color = args.arg(3).checkint();
202 | int w = args.arg(4).isnil() ? 1 : args.arg(4).checkint();
203 | int h = args.arg(5).isnil() ? 1 : args.arg(5).checkint();
204 |
205 | Console.SCREEN.fill(x, y, x + w - 1, y + h - 1, color);
206 | return NIL;
207 | }
208 | }
209 |
210 | private class write extends VarArgFunction {
211 | public Varargs invoke(Varargs args) {
212 | String text = args.arg(1).toString();
213 | int color = args.arg(2).checkint();
214 | int x = args.arg(3).checkint();
215 | int y = args.arg(4).checkint();
216 |
217 | Console.SCREEN.write(text, color, x, y);
218 | return NIL;
219 | }
220 | }
221 |
222 | // note for next interface version: change arguments order
223 | private class spr extends VarArgFunction {
224 | public Varargs invoke(Varargs args) {
225 | int id = args.arg(1).checkint();
226 | int x = args.arg(2).checkint();
227 | int y = args.arg(3).checkint();
228 |
229 | int scale = args.arg(4).isnil() ? 1 : args.arg(4).checkint();
230 |
231 | int sw = args.arg(5).isnil() ? 1 : args.arg(5).checkint();
232 | int sh = args.arg(6).isnil() ? 1 : args.arg(6).checkint();
233 |
234 | int rot = args.arg(7).isnil() ? 0 : args.arg(7).checkint();
235 |
236 | boolean hflip = args.arg(8).isnil() ? false : args.arg(8).checkboolean();
237 | boolean vflip = args.arg(9).isnil() ? false : args.arg(9).checkboolean();
238 |
239 | int xSprite = id % 16;
240 | int ySprite = id / 16;
241 |
242 | if(id < 0 || id >= 256) throw new LuaError("bad argument: id");
243 | if(scale <= 0) throw new LuaError("bad argument: scale");
244 | if(sw <= 0 || xSprite + sw > 16) throw new LuaError("bad argument: sw");
245 | if(sh <= 0 || ySprite + sh > 16) throw new LuaError("bad argument: sh");
246 |
247 | // flip is applied before rotation
248 | Console.SCREEN.draw(game.getSprite(xSprite, ySprite, sw, sh)
249 | .getFlipped(hflip, vflip)
250 | .getRotated(rot)
251 | .getScaled(scale),
252 | x, y);
253 |
254 | return NIL;
255 | }
256 | }
257 |
258 | //---MAP---\\
259 |
260 | private class get_tile extends TwoArgFunction {
261 | public LuaValue call(LuaValue x, LuaValue y) {
262 | int xt = x.checkint();
263 | int yt = y.checkint();
264 |
265 | if(xt < 0 || xt >= game.map.width) throw new LuaError("bad argument: x");
266 | if(yt < 0 || yt >= game.map.height) throw new LuaError("bad argument: y");
267 |
268 | return valueOf(game.map.getTile(xt, yt));
269 | }
270 | }
271 |
272 | // note for next interface version: change to set_tile(id, x, y)
273 | private class set_tile extends ThreeArgFunction {
274 | public LuaValue call(LuaValue x, LuaValue y, LuaValue idArg) {
275 | int xt = x.checkint();
276 | int yt = y.checkint();
277 | int id = idArg.checkint();
278 |
279 | if(xt < 0 || xt >= game.map.width) throw new LuaError("bad argument: x");
280 | if(yt < 0 || yt >= game.map.height) throw new LuaError("bad argument: y");
281 | if(id < 0 || id >= 256) throw new LuaError("bad argument: id");
282 |
283 | game.map.setTile(xt, yt, id);
284 | return NIL;
285 | }
286 | }
287 |
288 | // consider changing the arguments from offset to position (eg. draw on (x, y), not offset)
289 | private class maprender extends ThreeArgFunction {
290 | public LuaValue call(LuaValue scaleArg, LuaValue xOffArg, LuaValue yOffArg) {
291 | int scale = scaleArg.isnil() ? 1 : scaleArg.checkint();
292 | int xoff = xOffArg.isnil() ? 0 : xOffArg.checkint();
293 | int yoff = yOffArg.isnil() ? 0 : yOffArg.checkint();
294 |
295 | if(scale <= 0) throw new LuaError("bad argument: scale");
296 |
297 | game.map.render(Console.SCREEN, game, xoff, yoff, scale);
298 | return NIL;
299 | }
300 | }
301 |
302 | //---SAVE---\\
303 |
304 | private class save_data extends OneArgFunction {
305 | public LuaValue call(LuaValue saveTable) {
306 | return LuaValue.valueOf(game.saveSystem.serialize(saveTable.checktable()));
307 | }
308 | }
309 |
310 | private class load_data extends OneArgFunction {
311 | public LuaValue call(LuaValue arg) {
312 | return game.saveSystem.deserialize();
313 | }
314 | }
315 |
316 | }
317 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/interfaces/LuaInterface.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game.interfaces;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import org.luaj.vm2.Globals;
7 |
8 | import vulc.luag.game.Game;
9 |
10 | /** versioning: major.minor
11 | * major -> backward compatibility with other major versions is broken
12 | * minor -> backward compatibility with the same major version is not broken
13 | *
14 | * eg. 6.4 can run using an interface 6.7,
15 | * but 6.7 cannot run using an interface 6.4
16 | */
17 | public abstract class LuaInterface {
18 |
19 | public static final Map> INTERFACES =
20 | new HashMap>();
21 | public static final Map MINOR_VERSIONS = new HashMap();
22 |
23 | public static final int DEFAULT_MAJOR_VERSION = 1;
24 |
25 | static {
26 | INTERFACES.put(1, Interface001.class);
27 | MINOR_VERSIONS.put(1, 4);
28 | }
29 |
30 | protected final Game game;
31 | protected final Globals env;
32 |
33 | public LuaInterface(Game game, Globals env) {
34 | this.game = game;
35 | this.env = env;
36 | }
37 |
38 | public abstract void init();
39 |
40 | public static LuaInterface getInterface(int majorVersion, Game game, Globals env) {
41 | try {
42 | Class extends LuaInterface> interfaceClass = INTERFACES.get(majorVersion);
43 | if(interfaceClass != null) {
44 | return interfaceClass.getConstructor(Game.class, Globals.class).newInstance(game, env);
45 | }
46 | } catch(Exception e) {
47 | e.printStackTrace();
48 | }
49 | return null;
50 | }
51 |
52 | public static int minorVersion(int majorVersion) {
53 | return MINOR_VERSIONS.get(majorVersion);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/map/Map.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game.map;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.DataInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 |
8 | import vulc.luag.Console;
9 | import vulc.luag.game.Game;
10 | import vulc.luag.gfx.Screen;
11 |
12 | public class Map {
13 |
14 | public final int width, height;
15 | public final byte[] tiles;
16 |
17 | public Map(int w, int h) {
18 | this.width = w;
19 | this.height = h;
20 | this.tiles = new byte[w * h];
21 | for(int i = 0; i < tiles.length; i++) {
22 | tiles[i] = -128;
23 | }
24 | }
25 |
26 | public void render(Screen screen, Game game, int xOffset, int yOffset, int scale) {
27 | int tSize = Game.SPR_SIZE * scale;
28 |
29 | int xt0 = Math.floorDiv(xOffset, tSize);
30 | int yt0 = Math.floorDiv(yOffset, tSize);
31 | int xt1 = xt0 + (Console.WIDTH / tSize) + 1;
32 | int yt1 = yt0 + (Console.HEIGHT / tSize) + 1;
33 |
34 | for(int yt = yt0; yt < yt1; yt++) {
35 | if(yt < 0 || yt >= height) continue;
36 |
37 | for(int xt = xt0; xt < xt1; xt++) {
38 | if(xt < 0 || xt >= width) continue;
39 |
40 | int id = getTile(xt, yt);
41 | screen.draw(game.getSprite(id, 1, 1).getScaled(scale),
42 | xt * Game.SPR_SIZE * scale - xOffset,
43 | yt * Game.SPR_SIZE * scale - yOffset);
44 | }
45 | }
46 | }
47 |
48 | public int getTile(int x, int y) {
49 | return tiles[x + y * width] + 128;
50 | }
51 |
52 | public void setTile(int x, int y, int id) {
53 | tiles[x + y * width] = (byte) (id - 128);
54 | }
55 |
56 | public static Map load(InputStream inputStream) {
57 | try {
58 | DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream));
59 |
60 | int w = in.readInt();
61 | int h = in.readInt();
62 | Map map = new Map(w, h);
63 |
64 | for(int i = 0; i < map.tiles.length; i++) {
65 | int data = in.read();
66 | if(data == -1) {
67 | Console.die("Error:\n"
68 | + "map file is malformed\n"
69 | + "(not enought tile data)");
70 | return null;
71 | }
72 | map.tiles[i] = (byte) (data - 128);
73 | }
74 | in.close();
75 | return map;
76 | } catch(IOException e) {
77 | throw new RuntimeException(e);
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/vulc/luag/game/save/SaveSystem.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.game.save;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.DataInputStream;
7 | import java.io.DataOutputStream;
8 | import java.io.FileInputStream;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.io.OutputStream;
12 |
13 | import org.luaj.vm2.LuaError;
14 | import org.luaj.vm2.LuaTable;
15 | import org.luaj.vm2.LuaValue;
16 |
17 | import vulc.luag.Console;
18 | import vulc.luag.gfx.Icons;
19 | import vulc.vdf.ObjectTag;
20 |
21 | public class SaveSystem {
22 |
23 | public static final String SAVE_EXTENSION = "sav";
24 | public static final int MAX_SIZE = 256 * 1024; // 256 KB
25 | public static final int SAVE_DELAY = 60; // 1 sec
26 |
27 | private final String saveFile;
28 |
29 | private int lastSave = 0;
30 | private boolean hasLoaded = false;
31 |
32 | public SaveSystem(String cartridgeFile) {
33 | this.saveFile = cartridgeFile + "." + SAVE_EXTENSION;
34 | }
35 |
36 | public void tick() {
37 | // render the "save" icon only if the action was performed recently
38 | if(Console.ticks - lastSave > SAVE_DELAY) return;
39 |
40 | Console.SCREEN.drawBool(Icons.SAVE, 0xffffff,
41 | ((SAVE_DELAY - (Console.ticks - 1 - lastSave)) * 0xff / SAVE_DELAY),
42 | 151, 3);
43 | }
44 |
45 | public int serialize(LuaTable saveTable) {
46 | Console.LOGGER.info("Saving game data...");
47 |
48 | // if the save action was performed recently, don't save again
49 | if(Console.ticks - lastSave < SAVE_DELAY) {
50 | Console.LOGGER.severe("Save Error 1: trying to save too fast "
51 | + "(delay: " + SAVE_DELAY + " ticks)");
52 | return 1; // too fast
53 | }
54 |
55 | lastSave = Console.ticks;
56 |
57 | ObjectTag obj = new ObjectTag();
58 | addTableToObjectTag(obj, saveTable);
59 |
60 | ByteArrayOutputStream buffer = new ByteArrayOutputStream();
61 |
62 | try(DataOutputStream bufferOut = new DataOutputStream(buffer)) {
63 | obj.serialize(bufferOut);
64 | } catch(IOException e) {
65 | e.printStackTrace();
66 | }
67 |
68 | if(buffer.size() > MAX_SIZE) {
69 | Console.LOGGER.severe("Save Error 2: too much data "
70 | + "(max: " + MAX_SIZE + " bytes, sent: " + buffer.size() + ")");
71 | return 2; // too much data
72 | }
73 |
74 | try(OutputStream out = new BufferedOutputStream(new FileOutputStream(saveFile))) {
75 | synchronized(Console.DONT_STOP_LOCK) {
76 | out.write(buffer.toByteArray());
77 | }
78 | } catch(IOException e) {
79 | e.printStackTrace();
80 | }
81 |
82 | Console.LOGGER.info("Saving complete: " + buffer.size() + " bytes written");
83 | return 0; // ok
84 | }
85 |
86 | private static void addTableToObjectTag(ObjectTag obj, LuaTable table) {
87 | for(LuaValue keyLua : table.keys()) {
88 | LuaValue value = table.get(keyLua);
89 | String key = keyLua.toString();
90 |
91 | // add all valid values to the ObjectTag
92 | if(value.isboolean()) obj.setBoolean(key, value.checkboolean());
93 | else if(value.isint()) {
94 | int num = value.checkint();
95 |
96 | if((byte) num == num) obj.setByte(key, (byte) num);
97 | else if((short) num == num) obj.setShort(key, (short) num);
98 | else obj.setInt(key, num);
99 | // long is considered Double by luaj
100 | } else if(value.isnumber()) obj.setDouble(key, value.checkdouble());
101 | else if(value.isstring()) obj.setString(key, value.tojstring());
102 | else if(value.istable()) {
103 | ObjectTag subObj = new ObjectTag();
104 | addTableToObjectTag(subObj, value.checktable());
105 | obj.setObject(key, subObj);
106 | } else throw new LuaError("bad argument: type is " + value.typename());
107 | }
108 | }
109 |
110 | public LuaValue deserialize() {
111 | Console.LOGGER.info("Loading game data...");
112 |
113 | if(hasLoaded) {
114 | Console.LOGGER.severe("Load Error: data can be loaded only once");
115 | return LuaValue.NIL;
116 | }
117 | hasLoaded = true;
118 |
119 | ObjectTag obj = new ObjectTag();
120 | try(DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(saveFile)))) {
121 | obj.deserialize(in);
122 | } catch(IOException e) {
123 | e.printStackTrace();
124 | }
125 |
126 | LuaTable saveTable = new LuaTable();
127 | addObjectTagToTable(saveTable, obj);
128 |
129 | Console.LOGGER.info("Loading complete");
130 | return saveTable;
131 | }
132 |
133 | private static void addObjectTagToTable(LuaTable table, ObjectTag obj) {
134 | for(String key : obj.keySet()) {
135 | Object value = obj.getValue(key);
136 |
137 | LuaValue toAdd = null;
138 | if(value instanceof Boolean) toAdd = LuaValue.valueOf((boolean) value);
139 | else if(value instanceof Byte) toAdd = LuaValue.valueOf((byte) value);
140 | else if(value instanceof Short) toAdd = LuaValue.valueOf((short) value);
141 | else if(value instanceof Integer) toAdd = LuaValue.valueOf((int) value);
142 | else if(value instanceof Double) toAdd = LuaValue.valueOf((double) value);
143 | else if(value instanceof String) toAdd = LuaValue.valueOf((String) value);
144 | else if(value instanceof ObjectTag) {
145 | toAdd = new LuaTable();
146 | addObjectTagToTable((LuaTable) toAdd, (ObjectTag) value);
147 | } else {
148 | throw new LuaError("save file is malformed (contains invalid data type: "
149 | + value.getClass().getCanonicalName() + ")");
150 | }
151 | if(toAdd != null) table.set(key, toAdd);
152 | }
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/Colors.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx;
2 |
3 | public abstract class Colors {
4 |
5 | public static final int BACKGROUND_0 = 0xdd4444;
6 | public static final int BACKGROUND_1 = 0xaa4444;
7 |
8 | public static final int FOREGROUND_0 = 0x000000;
9 | public static final int FOREGROUND_1 = 0xeecccc;
10 | public static final int FOREGROUND_HIGHLIGHT = 0xffff55;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/ConsoleFrame.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx;
2 |
3 | import java.awt.Color;
4 | import java.awt.Dimension;
5 | import java.awt.Frame;
6 | import java.awt.Insets;
7 | import java.awt.event.WindowAdapter;
8 | import java.awt.event.WindowEvent;
9 | import java.io.IOException;
10 |
11 | import javax.imageio.ImageIO;
12 |
13 | import vulc.luag.Console;
14 |
15 | // BUG try to do WIN+down when in full screen
16 | public class ConsoleFrame extends Frame {
17 |
18 | private static final long serialVersionUID = 1L;
19 |
20 | private int wOld = -1, hOld = -1;
21 |
22 | public void init() {
23 | setTitle(Console.NAME + " " + Console.VERSION);
24 | setBackground(Color.DARK_GRAY);
25 |
26 | try {
27 | setIconImage(ImageIO.read(Console.class.getResourceAsStream("/res/icon.png")));
28 | } catch(IOException e) {
29 | e.printStackTrace();
30 | }
31 |
32 | addWindowListener(new WindowAdapter() {
33 | public void windowClosing(WindowEvent e) {
34 | synchronized(Console.DONT_STOP_LOCK) {
35 | System.exit(0);
36 | }
37 | }
38 |
39 | public void windowIconified(WindowEvent e) {
40 | Console.stop();
41 | }
42 |
43 | public void windowDeiconified(WindowEvent e) {
44 | Console.start();
45 | }
46 | });
47 | }
48 |
49 | public void checkSize() {
50 | Dimension d = getSize();
51 | Insets insets = getInsets();
52 | int wFrame = d.width - insets.left - insets.right;
53 | int hFrame = d.height - insets.top - insets.bottom;
54 |
55 | if(wFrame != wOld || hFrame != hOld) {
56 | Console.updateScaledSize(wFrame, hFrame);
57 |
58 | wOld = wFrame;
59 | hOld = hFrame;
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/Icons.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx;
2 |
3 | import javax.imageio.ImageIO;
4 |
5 | import vulc.bitmap.Bitmap;
6 | import vulc.bitmap.BoolBitmap;
7 |
8 | public abstract class Icons {
9 |
10 | // GENERAL
11 | public static final Bitmap SHELL = loadIcon("/res/icons/shell.png");
12 | public static final Bitmap SAVE = loadIcon("/res/icons/save.png");
13 | public static final Bitmap UNDO = loadIcon("/res/icons/undo.png");
14 | public static final Bitmap REDO = loadIcon("/res/icons/redo.png");
15 | public static final Bitmap SELECTED = loadIcon("/res/icons/selected.png");
16 |
17 | // EDITORS
18 | public static final Bitmap SPRITE_EDITOR = loadIcon("/res/icons/editor/sprite_editor.png");
19 | public static final Bitmap MAP_EDITOR = loadIcon("/res/icons/editor/map_editor.png");
20 |
21 | // TOOLS
22 | public static final Bitmap PENCIL_TOOL = loadIcon("/res/icons/editor/tool/pencil.png");
23 | public static final Bitmap BUCKET_TOOL = loadIcon("/res/icons/editor/tool/bucket.png");
24 | public static final Bitmap PICKUP_TOOL = loadIcon("/res/icons/editor/tool/pickup.png");
25 | public static final Bitmap SELECT_TOOL = loadIcon("/res/icons/editor/tool/select.png");
26 |
27 | // SPRITE EDITOR
28 | public static final Bitmap SPRITE_SCOPE_1 = loadIcon("/res/icons/editor/sprite/scope_1.png");
29 | public static final Bitmap SPRITE_SCOPE_2 = loadIcon("/res/icons/editor/sprite/scope_2.png");
30 |
31 | private static Bitmap loadIcon(String icon) {
32 | try {
33 | return new BoolBitmap(ImageIO.read(Icons.class.getResourceAsStream(icon)), 0x000000);
34 | } catch(Exception e) {
35 | throw new RuntimeException(e);
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/Screen.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx;
2 |
3 | import vulc.bitmap.IntBitmap;
4 | import vulc.bitmap.font.Font;
5 |
6 | public class Screen extends IntBitmap {
7 |
8 | public static final Font FONT;
9 | static {
10 | FONT = new Font(Screen.class.getResourceAsStream("/res/font.fv3"));
11 |
12 | FONT.setLetterSpacing(1);
13 | FONT.setLineSpacing(1);
14 | }
15 |
16 | public Screen(int width, int height) {
17 | super(width, height);
18 | setFont(FONT);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUIButton.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | public class GUIButton extends GUILabel {
4 |
5 | public Runnable onMouseDownAction = null;
6 | public Runnable onMousePressAction = null;
7 | public Runnable onMouseReleaseAction = null;
8 |
9 | public GUIButton(int x, int y, int w, int h) {
10 | super(x, y, w, h);
11 | }
12 |
13 | public void onMouseDown(int xMouse, int yMouse) {
14 | if(onMouseDownAction != null) onMouseDownAction.run();
15 | }
16 |
17 | public void onMousePress(int xMouse, int yMouse) {
18 | if(onMousePressAction != null) onMousePressAction.run();
19 | }
20 |
21 | public void onMouseRelease(int xMouse, int yMouse) {
22 | if(onMouseReleaseAction != null) onMouseReleaseAction.run();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUIComponent.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | import vulc.luag.gfx.Screen;
4 |
5 | public class GUIComponent {
6 |
7 | public int x, y;
8 | public int w, h;
9 |
10 | public boolean mouseInside = false;
11 | public boolean focused = false;
12 |
13 | public boolean opaque = false;
14 | public int background = 0xDDDDDD;
15 |
16 | public GUIComponent(int x, int y, int w, int h) {
17 | this.x = x;
18 | this.y = y;
19 | this.w = w;
20 | this.h = h;
21 | }
22 |
23 | public void tick() {
24 | }
25 |
26 | public void render(Screen screen) {
27 | if(opaque) screen.fill(x,
28 | y,
29 | x + w - 1,
30 | y + h - 1,
31 | background);
32 | }
33 |
34 | protected boolean isPointInside(int x, int y) {
35 | return x >= 0 && x < w && y >= 0 && y < h;
36 | }
37 |
38 | public void onMouseDown(int xMouse, int yMouse) {
39 | }
40 |
41 | public void onMousePress(int xMouse, int yMouse) {
42 | }
43 |
44 | public void onMouseRelease(int xMouse, int yMouse) {
45 | }
46 |
47 | public void onMouseInside(int xMouse, int yMouse) {
48 | }
49 |
50 | public void onMouseEnter() {
51 | }
52 |
53 | public void onMouseExit() {
54 | }
55 |
56 | public void onGainFocus() {
57 | }
58 |
59 | public void onLostFocus() {
60 | }
61 |
62 | public void onKeyPress(char character) {
63 | }
64 |
65 | public void onMouseScroll(int xMouse, int yMouse, int count) {
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUILabel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | import vulc.bitmap.Bitmap;
4 | import vulc.luag.gfx.Screen;
5 |
6 | public class GUILabel extends GUIComponent {
7 |
8 | public String text = "";
9 | public int textColor = 0;
10 |
11 | public Bitmap boolImage;
12 | public int colorAsBool;
13 |
14 | public Bitmap image;
15 |
16 | public GUILabel(int x, int y, int w, int h) {
17 | super(x, y, w, h);
18 | }
19 |
20 | public void setImage(Bitmap image, int color) {
21 | this.boolImage = image;
22 | this.colorAsBool = color;
23 |
24 | this.image = null;
25 | }
26 |
27 | public void setImage(Bitmap image) {
28 | this.image = image;
29 |
30 | this.boolImage = null;
31 | }
32 |
33 | public void render(Screen screen) {
34 | super.render(screen);
35 | screen.write(text, textColor, x + 1, y + (h - Screen.FONT.getHeight()) / 2);
36 |
37 | if(boolImage != null) {
38 | screen.drawBool(boolImage, colorAsBool,
39 | x + (w - boolImage.width) / 2,
40 | y + (h - boolImage.height) / 2);
41 | } else if(image != null) {
42 | screen.draw(image,
43 | x + (w - image.width) / 2,
44 | y + (h - image.height) / 2);
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUIMainPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | import java.awt.event.KeyAdapter;
4 | import java.awt.event.KeyEvent;
5 | import java.awt.event.MouseEvent;
6 | import java.awt.event.MouseWheelEvent;
7 | import java.awt.event.MouseWheelListener;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import vulc.luag.Console;
12 | import vulc.luag.input.InputHandler;
13 | import vulc.luag.input.InputHandler.Key;
14 | import vulc.luag.input.InputHandler.KeyType;
15 |
16 | public class GUIMainPanel extends GUIPanel {
17 |
18 | public final InputHandler input = new InputHandler();
19 |
20 | private final List keyBuffer = new ArrayList();
21 | private final KeyAdapter keyListener = new KeyAdapter() {
22 | public void keyPressed(KeyEvent e) {
23 | keyBuffer.add(e.getKeyChar());
24 | }
25 | };
26 |
27 | private final Key mouse1 = input.new Key(KeyType.MOUSE, MouseEvent.BUTTON1);
28 |
29 | private int wheelRotCount = 0;
30 | private final MouseWheelListener wheelListener = new MouseWheelListener() {
31 | public void mouseWheelMoved(MouseWheelEvent e) {
32 | wheelRotCount += e.getWheelRotation();
33 | }
34 | };
35 |
36 | public GUIMainPanel(int x, int y, int w, int h) {
37 | super(x, y, w, h);
38 | }
39 |
40 | public void init() {
41 | Console console = Console.instance;
42 |
43 | input.init();
44 | console.addKeyListener(keyListener);
45 | console.addMouseWheelListener(wheelListener);
46 | }
47 |
48 | public void tick() {
49 | super.tick();
50 |
51 | input.tick();
52 |
53 | int xMouse = (input.xMouse - Console.xOffset) * Console.WIDTH / Console.scaledWidth - this.x;
54 | int yMouse = (input.yMouse - Console.yOffset) * Console.HEIGHT / Console.scaledHeight - this.y;
55 |
56 | while(keyBuffer.size() != 0) {
57 | char c = keyBuffer.remove(0);
58 | this.onKeyPress(c);
59 | }
60 |
61 | if(mouse1.isKeyDown()) {
62 | if(this.isPointInside(xMouse, yMouse)) {
63 | this.onMouseDown(xMouse, yMouse);
64 | }
65 | }
66 |
67 | if(mouse1.isPressed()) {
68 | if(this.isPointInside(xMouse, yMouse)) {
69 | this.onMousePress(xMouse, yMouse);
70 | }
71 | }
72 | if(mouse1.isReleased()) {
73 | if(this.isPointInside(xMouse, yMouse)) {
74 | this.onMouseRelease(xMouse, yMouse);
75 | }
76 | }
77 |
78 | // do this even if isPointInside is false
79 | this.onMouseInside(xMouse, yMouse);
80 |
81 | if(wheelRotCount != 0) {
82 | if(this.isPointInside(xMouse, yMouse)) {
83 | this.onMouseScroll(xMouse, yMouse, wheelRotCount);
84 | }
85 | wheelRotCount = 0;
86 | }
87 | }
88 |
89 | public void removeInputListeners() {
90 | Console console = Console.instance;
91 |
92 | input.remove();
93 | console.removeKeyListener(keyListener);
94 | console.removeMouseWheelListener(wheelListener);
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUIPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import vulc.luag.gfx.Screen;
7 |
8 | public class GUIPanel extends GUIComponent {
9 |
10 | protected final List comps = new ArrayList();
11 | public final Screen screen;
12 |
13 | public GUIPanel(int x, int y, int w, int h) {
14 | super(x, y, w, h);
15 | this.screen = new Screen(w, h);
16 | }
17 |
18 | public void tick() {
19 | for(int i = 0; i < comps.size(); i++) {
20 | GUIComponent comp = comps.get(i);
21 | comp.tick();
22 | }
23 | }
24 |
25 | public void render(Screen screen) {
26 | this.screen.clear(background);
27 | drawComponents();
28 | screen.draw(this.screen, x, y);
29 | }
30 |
31 | protected void drawComponents() {
32 | for(int i = 0; i < comps.size(); i++) {
33 | GUIComponent comp = comps.get(i);
34 | comp.render(this.screen);
35 | }
36 | }
37 |
38 | public void add(GUIComponent comp) {
39 | comps.add(comp);
40 | }
41 |
42 | public void remove(GUIComponent comp) {
43 | comps.remove(comp);
44 | }
45 |
46 | public void onMouseDown(int xMouse, int yMouse) {
47 | for(int i = 0; i < comps.size(); i++) {
48 | GUIComponent comp = comps.get(i);
49 |
50 | // relative coordinates
51 | int xr = xMouse - comp.x;
52 | int yr = yMouse - comp.y;
53 |
54 | if(comp.isPointInside(xr, yr)) {
55 | if(!comp.focused) {
56 | comp.focused = true;
57 | comp.onGainFocus();
58 | }
59 | comp.onMouseDown(xr, yr);
60 | } else {
61 | if(comp.focused) {
62 | comp.focused = false;
63 | comp.onLostFocus();
64 | }
65 | }
66 | }
67 | }
68 |
69 | public void onMousePress(int xMouse, int yMouse) {
70 | for(int i = 0; i < comps.size(); i++) {
71 | GUIComponent comp = comps.get(i);
72 |
73 | // relative coordinates
74 | int xr = xMouse - comp.x;
75 | int yr = yMouse - comp.y;
76 |
77 | if(comp.isPointInside(xr, yr)) {
78 | comp.onMousePress(xr, yr);
79 | }
80 | }
81 | }
82 |
83 | public void onMouseRelease(int xMouse, int yMouse) {
84 | for(int i = 0; i < comps.size(); i++) {
85 | GUIComponent comp = comps.get(i);
86 |
87 | // relative coordinates
88 | int xr = xMouse - comp.x;
89 | int yr = yMouse - comp.y;
90 |
91 | if(comp.isPointInside(xr, yr)) {
92 | comp.onMouseRelease(xr, yr);
93 | }
94 | }
95 | }
96 |
97 | public void onMouseInside(int xMouse, int yMouse) {
98 | for(int i = 0; i < comps.size(); i++) {
99 | GUIComponent comp = comps.get(i);
100 |
101 | // relative coordinates
102 | int xr = xMouse - comp.x;
103 | int yr = yMouse - comp.y;
104 |
105 | if(comp.isPointInside(xr, yr)) {
106 | if(!comp.mouseInside) {
107 | comp.mouseInside = true;
108 | comp.onMouseEnter();
109 | }
110 | comp.onMouseInside(xr, yr);
111 | } else {
112 | if(comp.mouseInside) {
113 | comp.mouseInside = false;
114 | comp.onMouseExit();
115 | }
116 | }
117 | }
118 | }
119 |
120 | public void onMouseExit() {
121 | for(int i = 0; i < comps.size(); i++) {
122 | GUIComponent comp = comps.get(i);
123 |
124 | if(comp.mouseInside) {
125 | comp.mouseInside = false;
126 | comp.onMouseExit();
127 | }
128 | }
129 | }
130 |
131 | public void onMouseScroll(int xMouse, int yMouse, int count) {
132 | for(int i = 0; i < comps.size(); i++) {
133 | GUIComponent comp = comps.get(i);
134 |
135 | // relative coordinates
136 | int xr = xMouse - comp.x;
137 | int yr = yMouse - comp.y;
138 |
139 | if(comp.isPointInside(xr, yr)) {
140 | comp.onMouseScroll(xr, yr, count);
141 | }
142 | }
143 | }
144 |
145 | public void onKeyPress(char character) {
146 | for(int i = 0; i < comps.size(); i++) {
147 | GUIComponent comp = comps.get(i);
148 | comp.onKeyPress(character);
149 | }
150 | }
151 |
152 | public void onLostFocus() {
153 | for(int i = 0; i < comps.size(); i++) {
154 | GUIComponent comp = comps.get(i);
155 |
156 | if(comp.focused) {
157 | comp.focused = false;
158 | comp.onLostFocus();
159 | }
160 | }
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/gui/GUITextBox.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.gui;
2 |
3 | public class GUITextBox extends GUILabel {
4 |
5 | public static final int ALL_TEXT = 0;
6 | public static final int DEC_ONLY = 1;
7 | public static final int HEX_ONLY = 2;
8 |
9 | public int acceptedText = ALL_TEXT;
10 | public int nChars = -1;
11 |
12 | public GUITextBox(int x, int y, int w, int h) {
13 | super(x, y, w, h);
14 | }
15 |
16 | public void onKeyPress(char character) {
17 | if(!focused) return;
18 | if(character == '\b') {
19 | if(text.length() > 0) text = text.substring(0, text.length() - 1);
20 | } else if(character == '\n') {
21 | onEnterPress();
22 | } else {
23 | if(text.length() == nChars) return;
24 | boolean canWrite = false;
25 | switch(acceptedText) {
26 | case ALL_TEXT:
27 | if(character >= ' ' && character <= '~')
28 | canWrite = true;
29 | break;
30 |
31 | case DEC_ONLY:
32 | if(character >= '0' && character <= '9')
33 | canWrite = true;
34 | break;
35 | case HEX_ONLY:
36 | if((character >= '0' && character <= '9')
37 | || (character >= 'A' && character <= 'F')
38 | || (character >= 'a' && character <= 'f')) {
39 | canWrite = true;
40 | }
41 | break;
42 | }
43 | if(canWrite) text += character;
44 | }
45 | }
46 |
47 | public void onEnterPress() {
48 | focused = false;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/BootPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.gfx.Screen;
5 |
6 | public class BootPanel extends Panel {
7 |
8 | public Panel nextPanel;
9 | private int bootTime = 135; // 2.25s
10 | private boolean hasInit = false;
11 | private int animationTicks = 0;
12 |
13 | public BootPanel() {
14 | Console.SCREEN.clear(0);
15 | }
16 |
17 | public void init() {
18 | new Thread() {
19 | public void run() {
20 | nextPanel.init();
21 | hasInit = true;
22 | }
23 | }.start();
24 | }
25 |
26 | public void tick() {
27 | Screen screen = Console.SCREEN;
28 |
29 | screen.write(Console.NAME + "\n"
30 | + Console.COPYRIGHT + "\n"
31 | + "Version: " + Console.VERSION,
32 | 0xffffff, 1, 1);
33 |
34 | bootTime--;
35 | if(bootTime <= 0) {
36 | if(hasInit) {
37 | Console.currentPanel = nextPanel; // cannot call console.switchToPanel because it'd call panel.init() again
38 | nextPanel.onShow();
39 | screen.clear(0);
40 | } else {
41 | int animatPhase = animationTicks / 30 % 4;
42 | String text = null;
43 | if(animatPhase == 0) text = "Loading";
44 | else if(animatPhase == 1) text = "Loading.";
45 | else if(animatPhase == 2) text = "Loading..";
46 | else if(animatPhase == 3) text = "Loading...";
47 |
48 | Console.SCREEN.clear(0);
49 | Console.SCREEN.write(text, 0xffffff, 1, 1);
50 |
51 | animationTicks++;
52 | }
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/DeathPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.gfx.Screen;
5 |
6 | public class DeathPanel extends Panel {
7 |
8 | private final int background = 0x0000cc;
9 | private final int foreground = 0xffffff;
10 |
11 | private final String text;
12 | private boolean hasTicked = false;
13 |
14 | public DeathPanel(String text) {
15 | this.text = text;
16 | }
17 |
18 | public void tick() {
19 | if(hasTicked) return;
20 | hasTicked = true;
21 |
22 | Screen screen = Console.SCREEN;
23 | screen.clear(background);
24 |
25 | screen.write(text, foreground, 1, 1);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/EditorPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.editor.Editor;
5 | import vulc.luag.editor.map.MapEditor;
6 | import vulc.luag.editor.sprite.SpriteEditor;
7 | import vulc.luag.game.Game;
8 | import vulc.luag.gfx.Colors;
9 | import vulc.luag.gfx.Icons;
10 | import vulc.luag.gfx.gui.GUIButton;
11 | import vulc.luag.gfx.gui.GUILabel;
12 | import vulc.luag.gfx.gui.GUIMainPanel;
13 | import vulc.luag.gfx.gui.GUIPanel;
14 |
15 | public class EditorPanel extends Panel {
16 |
17 | private final int btnDist = 3;
18 |
19 | private final GUIButton saveBtn;
20 | private final GUILabel footerLabel;
21 |
22 | public final Game game;
23 | public final GUIMainPanel mainPanel;
24 | public Editor currentEditor;
25 |
26 | public Editor mapEditor;
27 | public Editor spriteEditor;
28 |
29 | public EditorPanel() {
30 | this.game = new Game();
31 | mainPanel = new GUIMainPanel(0, 0, Console.SCREEN.width, Console.SCREEN.height);
32 | mainPanel.background = 0x000000;
33 | mainPanel.init();
34 |
35 | //
36 | //---HEADER---\\
37 | //
38 |
39 | GUIPanel headerPanel = new GUIPanel(0, 0, mainPanel.w, 10);
40 | headerPanel.background = Colors.BACKGROUND_0;
41 | mainPanel.add(headerPanel);
42 |
43 | GUIButton shellBtn = new GUIButton(1, 1, 8, 8);
44 | shellBtn.opaque = true;
45 | shellBtn.background = Colors.BACKGROUND_1;
46 | shellBtn.setImage(Icons.SHELL, Colors.FOREGROUND_1);
47 | shellBtn.onMousePressAction = () -> {
48 | Console.switchToPanel(new ShellPanel());
49 | };
50 | headerPanel.add(shellBtn);
51 |
52 | GUIButton mapEditBtn = new GUIButton(shellBtn.x + shellBtn.w + btnDist, 1, 8, 8);
53 | mapEditBtn.opaque = true;
54 | mapEditBtn.background = Colors.BACKGROUND_1;
55 | mapEditBtn.setImage(Icons.MAP_EDITOR, Colors.FOREGROUND_1);
56 | mapEditBtn.onMousePressAction = () -> {
57 | switchToEditor(mapEditor);
58 | };
59 | headerPanel.add(mapEditBtn);
60 |
61 | GUIButton sprEditBtn = new GUIButton(mapEditBtn.x + mapEditBtn.w + btnDist, 1, 8, 8);
62 | sprEditBtn.opaque = true;
63 | sprEditBtn.background = Colors.BACKGROUND_1;
64 | sprEditBtn.setImage(Icons.SPRITE_EDITOR, Colors.FOREGROUND_1);
65 | sprEditBtn.onMousePressAction = () -> {
66 | switchToEditor(spriteEditor);
67 | };
68 | headerPanel.add(sprEditBtn);
69 |
70 | saveBtn = new GUIButton(headerPanel.w - 9, 1, 8, 8);
71 | saveBtn.opaque = true;
72 | saveBtn.background = Colors.BACKGROUND_1;
73 | saveBtn.setImage(Icons.SAVE, Colors.FOREGROUND_1);
74 | saveBtn.onMousePressAction = () -> {
75 | Console.LOGGER.info("saving");
76 |
77 | mapEditor.onSave();
78 | spriteEditor.onSave();
79 | };
80 | headerPanel.add(saveBtn);
81 |
82 | //
83 | //---FOOTER---\\
84 | //
85 |
86 | GUIPanel footerPanel = new GUIPanel(0, mainPanel.h - 10, mainPanel.w, 10);
87 | footerPanel.background = Colors.BACKGROUND_0;
88 | mainPanel.add(footerPanel);
89 |
90 | footerLabel = new GUILabel(1, 1, footerPanel.w - 2, 8);
91 | footerLabel.textColor = Colors.FOREGROUND_1;
92 | footerPanel.add(footerLabel);
93 | }
94 |
95 | public void init() {
96 | if(!game.initDevResources()) return;
97 |
98 | mapEditor = new MapEditor(this, 0, 10, mainPanel.w, mainPanel.h - 20);
99 | spriteEditor = new SpriteEditor(this, 0, 10, mainPanel.w, mainPanel.h - 20);
100 |
101 | switchToEditor(mapEditor);
102 | }
103 |
104 | public void remove() {
105 | game.remove();
106 |
107 | if(mapEditor != null) mapEditor.remove();
108 | if(spriteEditor != null) spriteEditor.remove();
109 |
110 | mainPanel.removeInputListeners();
111 | }
112 |
113 | public void tick() {
114 | currentEditor.tick();
115 | mainPanel.tick();
116 | mainPanel.render(Console.SCREEN);
117 |
118 | if(mapEditor.shouldSave()
119 | || spriteEditor.shouldSave()) {
120 | saveBtn.colorAsBool = Colors.FOREGROUND_HIGHLIGHT;
121 | } else {
122 | saveBtn.colorAsBool = Colors.FOREGROUND_1;
123 | }
124 | }
125 |
126 | private void switchToEditor(Editor editor) {
127 | if(currentEditor != null) currentEditor.remove();
128 | editor.onShow();
129 | currentEditor = editor;
130 |
131 | footerLabel.text = editor.getTitle();
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/GamePanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.game.Game;
5 |
6 | public class GamePanel extends Panel {
7 |
8 | private final Game game;
9 |
10 | public GamePanel() {
11 | this.game = new Game();
12 | }
13 |
14 | public void init() {
15 | try {
16 | if(Console.cartridge != null) {
17 | if(!game.initCartridgeResources()) return;
18 | } else {
19 | if(!game.initDevResources()) return;
20 | }
21 | game.initScript();
22 | } catch(Exception e) {
23 | // no error should be uncaught
24 | // this prevents the console to crash
25 | Console.die("Error:\n"
26 | + "uncaught error");
27 | e.printStackTrace();
28 | }
29 | }
30 |
31 | public void remove() {
32 | game.remove();
33 |
34 | // Game's interface can set screen's transparent colors.
35 | // This will reset it.
36 | Console.SCREEN.setTransparent();
37 | }
38 |
39 | public void tick() {
40 | game.tick();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/Panel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | public abstract class Panel {
4 |
5 | public void init() {
6 | }
7 |
8 | public void onShow() {
9 | }
10 |
11 | public void remove() {
12 | }
13 |
14 | public abstract void tick();
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/vulc/luag/gfx/panel/ShellPanel.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.gfx.panel;
2 |
3 | import java.awt.event.KeyAdapter;
4 | import java.awt.event.KeyEvent;
5 | import java.awt.event.MouseWheelEvent;
6 | import java.awt.event.MouseWheelListener;
7 |
8 | import vulc.luag.Console;
9 | import vulc.luag.input.InputHandler;
10 | import vulc.luag.input.InputHandler.Key;
11 | import vulc.luag.input.InputHandler.KeyType;
12 | import vulc.luag.shell.Shell;
13 | import vulc.luag.shell.ShellChar;
14 |
15 | public class ShellPanel extends Panel {
16 |
17 | private final InputHandler input = new InputHandler();
18 | public final Key ctrl = input.new Key(KeyType.KEYBOARD, KeyEvent.VK_CONTROL);
19 |
20 | private final KeyAdapter keyListener = new KeyAdapter() {
21 | public void keyPressed(KeyEvent e) {
22 | Shell.USER_BUFFER.add(new ShellChar(e.getKeyChar(), Shell.USER_FOREGROUND));
23 |
24 | int code = e.getKeyCode();
25 | if(code == KeyEvent.VK_UP)
26 | Shell.pressedUP = true;
27 | else if(code == KeyEvent.VK_LEFT)
28 | Shell.pressedLEFT = true;
29 | else if(code == KeyEvent.VK_DOWN)
30 | Shell.pressedDOWN = true;
31 | else if(code == KeyEvent.VK_RIGHT)
32 | Shell.pressedRIGHT = true;
33 | }
34 | };
35 | private final MouseWheelListener mouseScrollListener = new MouseWheelListener() {
36 | public void mouseWheelMoved(MouseWheelEvent e) {
37 | Shell.scrollBuffer += e.getWheelRotation();
38 | }
39 | };
40 |
41 | public ShellPanel() {
42 | Shell.panel = this;
43 | }
44 |
45 | public void onShow() {
46 | Console console = Console.instance;
47 |
48 | input.init();
49 | console.addKeyListener(keyListener);
50 | console.addMouseWheelListener(mouseScrollListener);
51 | }
52 |
53 | public void tick() {
54 | input.tick();
55 | Shell.tick();
56 | }
57 |
58 | public void remove() {
59 | Console console = Console.instance;
60 |
61 | input.remove();
62 | console.removeKeyListener(keyListener);
63 | console.removeMouseWheelListener(mouseScrollListener);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/vulc/luag/input/FullScreenListener.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.input;
2 |
3 | import java.awt.event.KeyEvent;
4 | import java.awt.event.KeyListener;
5 |
6 | import vulc.luag.Console;
7 |
8 | public class FullScreenListener implements KeyListener {
9 |
10 | public void keyTyped(KeyEvent e) {
11 | }
12 |
13 | public void keyPressed(KeyEvent e) {
14 | if(e.getKeyCode() == KeyEvent.VK_F11) {
15 | Console.switchFullScreen();
16 | }
17 | }
18 |
19 | public void keyReleased(KeyEvent e) {
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/vulc/luag/input/InputHandler.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (C) 2019 Vulcalien
3 | * This code or part of it is licensed under MIT License by Vulcalien
4 | ******************************************************************************/
5 | package vulc.luag.input;
6 |
7 | import java.awt.event.FocusEvent;
8 | import java.awt.event.FocusListener;
9 | import java.awt.event.KeyEvent;
10 | import java.awt.event.KeyListener;
11 | import java.awt.event.MouseEvent;
12 | import java.awt.event.MouseListener;
13 | import java.awt.event.MouseMotionListener;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | import vulc.luag.Console;
18 |
19 | public class InputHandler implements KeyListener, MouseListener, MouseMotionListener, FocusListener {
20 |
21 | public static enum KeyType {
22 | KEYBOARD, MOUSE
23 | }
24 |
25 | public static enum KeyAction {
26 | PRESS, RELEASE
27 | }
28 |
29 | private final List keys = new ArrayList();
30 | private final List keyboardKeys = new ArrayList();
31 | private final List mouseKeys = new ArrayList();
32 |
33 | public int xMouse = -1, yMouse = -1;
34 |
35 | public void init() {
36 | Console console = Console.instance;
37 |
38 | console.setFocusTraversalKeysEnabled(false);
39 |
40 | console.addKeyListener(this);
41 | console.addMouseListener(this);
42 | console.addMouseMotionListener(this);
43 | console.addFocusListener(this);
44 | }
45 |
46 | public void remove() {
47 | Console console = Console.instance;
48 |
49 | releaseAll();
50 |
51 | console.removeKeyListener(this);
52 | console.removeMouseListener(this);
53 | console.removeMouseMotionListener(this);
54 | console.removeFocusListener(this);
55 | }
56 |
57 | public void tick() {
58 | for(int i = 0; i < keys.size(); i++) {
59 | keys.get(i).tick();
60 | }
61 | }
62 |
63 | private void releaseAll() {
64 | for(Key key : keys) {
65 | key.isKeyDown = false;
66 | key.wasKeyDown = false;
67 | }
68 | }
69 |
70 | private void receiveInput(KeyAction action, KeyType type, int code) {
71 | List keys = getList(type);
72 | for(Key key : keys) {
73 | if(key.code == code) {
74 | if(action == KeyAction.PRESS) {
75 | key.shouldStayDown = true;
76 | } else if(action == KeyAction.RELEASE) {
77 | key.shouldRelease = true;
78 | }
79 | }
80 | }
81 | }
82 |
83 | private List getList(KeyType type) {
84 | switch(type) {
85 | case KEYBOARD:
86 | return keyboardKeys;
87 |
88 | case MOUSE:
89 | return mouseKeys;
90 |
91 | default:
92 | return null;
93 | }
94 | }
95 |
96 | public void keyTyped(KeyEvent e) {
97 | }
98 |
99 | public void keyPressed(KeyEvent e) {
100 | receiveInput(KeyAction.PRESS, KeyType.KEYBOARD, e.getKeyCode());
101 | }
102 |
103 | public void keyReleased(KeyEvent e) {
104 | receiveInput(KeyAction.RELEASE, KeyType.KEYBOARD, e.getKeyCode());
105 | }
106 |
107 | public void mouseClicked(MouseEvent e) {
108 | }
109 |
110 | public void mousePressed(MouseEvent e) {
111 | receiveInput(KeyAction.PRESS, KeyType.MOUSE, e.getButton());
112 | }
113 |
114 | public void mouseReleased(MouseEvent e) {
115 | receiveInput(KeyAction.RELEASE, KeyType.MOUSE, e.getButton());
116 | }
117 |
118 | public void mouseEntered(MouseEvent e) {
119 | }
120 |
121 | public void mouseExited(MouseEvent e) {
122 | }
123 |
124 | public void mouseDragged(MouseEvent e) {
125 | xMouse = e.getX();
126 | yMouse = e.getY();
127 | }
128 |
129 | public void mouseMoved(MouseEvent e) {
130 | xMouse = e.getX();
131 | yMouse = e.getY();
132 | }
133 |
134 | public void focusGained(FocusEvent e) {
135 | }
136 |
137 | public void focusLost(FocusEvent e) {
138 | for(Key key : keys) {
139 | key.shouldRelease = true;
140 | }
141 | }
142 |
143 | public class Key {
144 |
145 | private KeyType type;
146 | private int code;
147 |
148 | private boolean shouldStayDown = false;
149 | private boolean shouldRelease = false;
150 |
151 | private boolean isKeyDown = false;
152 | private boolean wasKeyDown = false;
153 |
154 | public Key() {
155 | }
156 |
157 | public Key(KeyType type, int code) {
158 | init(type, code);
159 | }
160 |
161 | private void init(KeyType type, int code) {
162 | this.type = type;
163 | this.code = code;
164 |
165 | keys.add(this);
166 | getList(type).add(this);
167 | }
168 |
169 | private void tick() {
170 | wasKeyDown = isKeyDown;
171 | isKeyDown = shouldStayDown;
172 |
173 | if(shouldRelease) {
174 | shouldRelease = false;
175 | shouldStayDown = false;
176 | }
177 | }
178 |
179 | public void setKeyBinding(KeyType newType, int newCode) {
180 | if(this.type != null) getList(this.type).remove(this);
181 | init(newType, newCode);
182 | }
183 |
184 | public boolean isKeyDown() {
185 | return isKeyDown;
186 | }
187 |
188 | public boolean isPressed() {
189 | return !wasKeyDown && isKeyDown;
190 | }
191 |
192 | public boolean isReleased() {
193 | return wasKeyDown && !isKeyDown;
194 | }
195 |
196 | }
197 |
198 | }
199 |
--------------------------------------------------------------------------------
/src/vulc/luag/sfx/Sound.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (C) 2019 Vulcalien
3 | * This code or part of it is licensed under MIT License by Vulcalien
4 | ******************************************************************************/
5 | package vulc.luag.sfx;
6 |
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | import javax.sound.sampled.AudioInputStream;
11 | import javax.sound.sampled.AudioSystem;
12 | import javax.sound.sampled.Clip;
13 |
14 | public class Sound {
15 |
16 | private final InputStream inputStream;
17 | private Clip clip;
18 |
19 | public Sound(InputStream in) {
20 | this.inputStream = in;
21 | try {
22 | AudioInputStream ais = AudioSystem.getAudioInputStream(in);
23 | Clip clip = AudioSystem.getClip();
24 | clip.open(ais);
25 | this.clip = clip;
26 | } catch(Exception e) {
27 | e.printStackTrace();
28 | }
29 | }
30 |
31 | public void onRemove() {
32 | stop();
33 | try {
34 | inputStream.close();
35 | } catch(IOException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 |
40 | public void play() {
41 | if(clip == null) return;
42 | if(clip.isRunning()) clip.stop();
43 | clip.setFramePosition(0);
44 | clip.start();
45 | }
46 |
47 | public void loop() {
48 | if(clip == null) return;
49 | if(clip.isRunning()) clip.stop();
50 | clip.setFramePosition(0);
51 | clip.loop(Clip.LOOP_CONTINUOUSLY);
52 | }
53 |
54 | public void stop() {
55 | if(clip == null) return;
56 | clip.stop();
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/Shell.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import vulc.bitmap.font.Font;
7 | import vulc.luag.Console;
8 | import vulc.luag.gfx.Screen;
9 | import vulc.luag.gfx.panel.ShellPanel;
10 | import vulc.luag.shell.command.ShellCommand;
11 |
12 | public abstract class Shell {
13 |
14 | public static final int BACKGROUND = 0x000000;
15 | public static final int DEFAULT_FOREGROUND = 0xffffff;
16 | public static final int USER_FOREGROUND = 0x00ff00;
17 | public static final int ERROR_FOREGROUND = 0xff0000;
18 |
19 | public static final int HORIZONTAL_CHARS = Console.WIDTH / (Screen.FONT.widthOf(' ') + 1);
20 | public static final int VERTICAL_LINES = Console.HEIGHT / (Screen.FONT.getHeight() + 1);
21 |
22 | private static final int ANIMATION_DELAY = 25;
23 |
24 | public static final List CONSOLE_BUFFER = new ArrayList(); // chars written by the console
25 | public static final List USER_BUFFER = new ArrayList(); // chars written by the user
26 |
27 | public static int scrollBuffer = 0;
28 | public static boolean pressedUP = false, pressedLEFT = false, pressedDOWN = false, pressedRIGHT = false;
29 |
30 | private static final List CLOSED_ROWS = new ArrayList();
31 | private static ShellRow currentLine = new ShellRow();
32 | private static int currentChar = 0;
33 |
34 | private static final List COMMAND_HISTORY = new ArrayList();
35 | private static int historyPoint = 0;
36 |
37 | private static int renderOffset = 0;
38 | private static int animationTicks = 0; // cursor animation
39 |
40 | public static ShellPanel panel;
41 |
42 | private Shell() {
43 | }
44 |
45 | public static void init() {
46 | write(Console.NAME + "\n");
47 | write(Console.COPYRIGHT + "\n");
48 | write("Version: " + Console.VERSION + "\n");
49 | write("\n");
50 | }
51 |
52 | public static void tick() {
53 | if(CONSOLE_BUFFER.size() != 0) {
54 | ShellChar c = CONSOLE_BUFFER.remove(0);
55 | receiveInput(c, false);
56 |
57 | animationTicks = ANIMATION_DELAY;
58 | } else if(USER_BUFFER.size() != 0) {
59 | ShellChar c = USER_BUFFER.remove(0);
60 | receiveInput(c, true);
61 |
62 | animationTicks = 0;
63 | } else {
64 | animationTicks++;
65 | }
66 |
67 | // history
68 | byte historyShift = 0;
69 | if(pressedUP) {
70 | pressedUP = false;
71 | historyShift++;
72 | }
73 | if(pressedDOWN) {
74 | pressedDOWN = false;
75 | historyShift--;
76 | }
77 |
78 | if(historyShift != 0) {
79 | int newHistoryPoint = historyPoint + historyShift;
80 |
81 | if(newHistoryPoint >= 0 && newHistoryPoint < COMMAND_HISTORY.size()) {
82 | historyPoint = newHistoryPoint;
83 |
84 | // most recent command is 0
85 | currentLine = COMMAND_HISTORY.get(historyPoint).copy();
86 | currentChar = currentLine.size();
87 | }
88 | }
89 |
90 | if(scrollBuffer != 0) {
91 | int newOffset = renderOffset + scrollBuffer;
92 |
93 | // if is under the bottom then move back to bottom
94 | int lowestOffset = lowestOffset();
95 | if(newOffset > lowestOffset) {
96 | newOffset = lowestOffset;
97 | }
98 |
99 | // this may be caused by the previous if block
100 | if(newOffset < 0) newOffset = 0;
101 |
102 | renderOffset = newOffset;
103 | scrollBuffer = 0;
104 | }
105 |
106 | if(pressedLEFT) {
107 | pressedLEFT = false;
108 | if(currentChar > 0) {
109 | if(panel.ctrl.isKeyDown()) {
110 | currentChar = leftWordPosition();
111 | } else {
112 | currentChar--;
113 | }
114 | }
115 | }
116 | if(pressedRIGHT) {
117 | pressedRIGHT = false;
118 | if(currentChar < currentLine.size()) {
119 | if(panel.ctrl.isKeyDown()) {
120 | currentChar = rightWordPosition();
121 | } else {
122 | currentChar++;
123 | }
124 | }
125 | }
126 | render();
127 | }
128 |
129 | private static void render() {
130 | Console.SCREEN.clear(BACKGROUND);
131 |
132 | int margin = 1;
133 | int yRender = margin;
134 |
135 | for(int i = 0; i < VERTICAL_LINES; i++) {
136 | int line = i + renderOffset;
137 |
138 | if(line < CLOSED_ROWS.size()) {
139 | CLOSED_ROWS.get(line).render(Console.SCREEN, margin, yRender);
140 | yRender += Screen.FONT.getHeight() + Screen.FONT.getLineSpacing();
141 | } else {
142 | ShellRow[] splitCurrent = splitCurrentLine(currentLine);
143 | for(int a = 0; a < splitCurrent.length; a++) {
144 | splitCurrent[a].render(Console.SCREEN, margin, yRender);
145 | yRender += Screen.FONT.getHeight() + Screen.FONT.getLineSpacing();
146 | }
147 | break;
148 | }
149 | }
150 |
151 | // draw the cursor
152 | if(animationTicks / ANIMATION_DELAY % 2 == 0) {
153 | Font font = Screen.FONT;
154 | Console.SCREEN.write("_", DEFAULT_FOREGROUND,
155 | 1 + (font.widthOf(' ') + font.getLetterSpacing())
156 | * (currentChar % HORIZONTAL_CHARS),
157 | 1 + (font.getHeight() + font.getLineSpacing())
158 | * (currentChar / HORIZONTAL_CHARS + CLOSED_ROWS.size() - renderOffset));
159 | }
160 | }
161 |
162 | public static void receiveInput(ShellChar character, boolean shouldExecute) {
163 | int lowestOffset;
164 | switch(character.value) {
165 | case '\n':
166 | if(shouldExecute) execute(currentLine);
167 |
168 | ShellRow[] splitCurrent = splitCurrentLine(currentLine);
169 | for(int i = 0; i < splitCurrent.length; i++) {
170 | // here the text always ends with '\n'
171 | CLOSED_ROWS.add(splitCurrent[i]);
172 | }
173 | currentLine.clear();
174 | currentChar = 0;
175 |
176 | // if is not at bottom then move to bottom
177 | lowestOffset = lowestOffset();
178 | if(renderOffset < lowestOffset) {
179 | renderOffset = lowestOffset;
180 | }
181 | break;
182 |
183 | case '\b':
184 | if(currentLine.size() > 0 && currentChar > 0) {
185 | if(panel.ctrl.isKeyDown()) {
186 | int oldLength = currentLine.size();
187 | currentLine = currentLine.subrow(0, leftWordPosition())
188 | .join(currentLine.subrow(currentChar, currentLine.size()));
189 |
190 | currentChar -= oldLength - currentLine.size();
191 | } else {
192 | currentLine = currentLine.subrow(0, currentChar - 1)
193 | .join(currentLine.subrow(currentChar, currentLine.size()));
194 | currentChar--;
195 | }
196 | }
197 | break;
198 |
199 | case 127:
200 | if(currentLine.size() > 0 && currentChar != currentLine.size()) {
201 | if(panel.ctrl.isKeyDown()) {
202 | currentLine = currentLine.subrow(0, currentChar)
203 | .join(currentLine.subrow(rightWordPosition(), currentLine.size()));
204 | } else {
205 | currentLine = currentLine.subrow(0, currentChar)
206 | .join(currentLine.subrow(currentChar + 1, currentLine.size()));
207 | }
208 | }
209 | break;
210 |
211 | default:
212 | if(character.value >= 32 && character.value < 127) {
213 | currentLine = currentLine.subrow(0, currentChar)
214 | .join(character)
215 | .join(currentLine.subrow(currentChar, currentLine.size()));
216 | currentChar++;
217 |
218 | // if is not at bottom then move to bottom
219 | lowestOffset = lowestOffset();
220 | if(renderOffset < lowestOffset) {
221 | renderOffset = lowestOffset;
222 | }
223 | }
224 | break;
225 | }
226 | }
227 |
228 | public static void write(String text, int color) {
229 | for(int i = 0; i < text.length(); i++) {
230 | CONSOLE_BUFFER.add(new ShellChar(text.charAt(i), color));
231 | }
232 | }
233 |
234 | public static void write(String text) {
235 | write(text, DEFAULT_FOREGROUND);
236 | }
237 |
238 | public static void clear() {
239 | CLOSED_ROWS.clear();
240 | currentLine.clear();
241 | renderOffset = 0;
242 | }
243 |
244 | public static void execute(ShellRow row) {
245 | COMMAND_HISTORY.add(0, row.copy());
246 | historyPoint = -1;
247 |
248 | String line = row.toString();
249 | line = line.trim().replaceAll(" +", " ");
250 | if(!ShellCommand.execute(line)) {
251 | write("unknown command\n\n");
252 | }
253 | }
254 |
255 | private static ShellRow[] splitCurrentLine(ShellRow line) {
256 | int height = (line.size() - 1) / (Shell.HORIZONTAL_CHARS) + 1;
257 |
258 | ShellRow[] splitLine = new ShellRow[height];
259 | for(int i = 0; i < height; i++) {
260 | int start = i * Shell.HORIZONTAL_CHARS;
261 |
262 | int end = start;
263 | if(i != height - 1) {
264 | end += Shell.HORIZONTAL_CHARS;
265 | } else {
266 | // if length == HORIZONTAL_CHARS the % will be 0
267 | if(line.size() != 0
268 | && line.size() % Shell.HORIZONTAL_CHARS == 0) {
269 | end += Shell.HORIZONTAL_CHARS;
270 | } else {
271 | end += line.size() % (Shell.HORIZONTAL_CHARS);
272 | }
273 | }
274 | splitLine[i] = line.subrow(start, end);
275 | }
276 | return splitLine;
277 | }
278 |
279 | private static int lowestOffset() {
280 | int currentLineHeight = currentLine.size() / HORIZONTAL_CHARS + 1;
281 | return CLOSED_ROWS.size() - VERTICAL_LINES + currentLineHeight;
282 | }
283 |
284 | // find left word's position, used for ctrl+left and ctrl+'\b'
285 | private static int leftWordPosition() {
286 | int spacePosition = -1;
287 | boolean foundNonSpace = false;
288 | for(int i = currentChar - 1; i >= 0; i--) {
289 | if(currentLine.charAt(i) == ' ') {
290 | if(foundNonSpace) {
291 | spacePosition = i;
292 | break;
293 | }
294 | } else {
295 | foundNonSpace = true;
296 | }
297 | }
298 | return spacePosition + 1;
299 | }
300 |
301 | // find right word's position, used for ctrl+right and ctrl+del
302 | private static int rightWordPosition() {
303 | int nonSpacePosition = currentLine.size();
304 | boolean foundSpace = false;
305 | for(int i = currentChar; i < currentLine.size(); i++) {
306 | if(currentLine.charAt(i) != ' ') {
307 | if(foundSpace) {
308 | nonSpacePosition = i;
309 | break;
310 | }
311 | } else {
312 | foundSpace = true;
313 | }
314 | }
315 | return nonSpacePosition;
316 | }
317 |
318 | }
319 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/ShellChar.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell;
2 |
3 | public class ShellChar {
4 |
5 | public final char value;
6 | public final int color;
7 |
8 | public ShellChar(char value, int color) {
9 | this.value = value;
10 | this.color = color;
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/ShellRow.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell;
2 |
3 | import java.util.ArrayList;
4 |
5 | import vulc.bitmap.Bitmap;
6 | import vulc.luag.gfx.Screen;
7 |
8 | public class ShellRow extends ArrayList {
9 |
10 | private static final long serialVersionUID = 1L;
11 |
12 | public void render(Bitmap bitmap, int x, int y) {
13 | for(ShellChar c : this) {
14 | bitmap.write(c.value + "", c.color, x, y);
15 | x += Screen.FONT.widthOf(c.value) + Screen.FONT.getLetterSpacing();
16 | }
17 | }
18 |
19 | public char charAt(int index) {
20 | return get(index).value;
21 | }
22 |
23 | public ShellRow join(ShellChar c) {
24 | add(c);
25 | return this;
26 | }
27 |
28 | public ShellRow join(ShellRow row) {
29 | for(ShellChar c : row) {
30 | add(c);
31 | }
32 | return this;
33 | }
34 |
35 | public ShellRow subrow(int begin, int end) {
36 | ShellRow result = new ShellRow();
37 | for(int i = begin; i < end; i++) {
38 | result.add(get(i));
39 | }
40 | return result;
41 | }
42 |
43 | public String toString() {
44 | String string = "";
45 | for(ShellChar c : this) {
46 | string += c.value;
47 | }
48 | return string;
49 | }
50 |
51 | public ShellRow copy() {
52 | ShellRow newRow = new ShellRow();
53 | for(ShellChar c : this) {
54 | newRow.add(c);
55 | }
56 | return newRow;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/ClsCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.shell.Shell;
4 |
5 | public class ClsCommand extends ShellCommand {
6 |
7 | public ClsCommand() {
8 | super("cls", "clear");
9 | }
10 |
11 | public void run(String[] args) {
12 | Shell.clear();
13 | }
14 |
15 | protected String getHelpMessage() {
16 | return "clears the shell";
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/EditCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.gfx.panel.EditorPanel;
5 |
6 | public class EditCommand extends ShellCommand {
7 |
8 | public EditCommand() {
9 | super("edit", "editor");
10 | isDevelopersOnly = true;
11 | }
12 |
13 | public void run(String[] args) {
14 | Console.switchToPanel(new EditorPanel());
15 | }
16 |
17 | protected String getHelpMessage() {
18 | return "opens the game editor";
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/ExitCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | public class ExitCommand extends ShellCommand {
4 |
5 | public ExitCommand() {
6 | super("exit");
7 | }
8 |
9 | public void run(String[] args) {
10 | System.exit(0);
11 | }
12 |
13 | protected String getHelpMessage() {
14 | return "shuts down the console";
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/FilesCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import java.awt.Desktop;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import vulc.luag.Console;
8 | import vulc.luag.game.Game;
9 |
10 | public class FilesCommand extends ShellCommand {
11 |
12 | public FilesCommand() {
13 | super("files");
14 | isDevelopersOnly = true;
15 | }
16 |
17 | public void run(String[] args) {
18 | if(Desktop.isDesktopSupported()) {
19 | Desktop desktop = Desktop.getDesktop();
20 |
21 | File folder = new File(Game.USERDATA_DIR);
22 | if(!folder.isDirectory()) {
23 | Console.die("Error:\n"
24 | + "'" + Game.USERDATA_DIR_NAME + "'\n"
25 | + "folder not found");
26 | return;
27 | }
28 |
29 | try {
30 | desktop.open(folder);
31 | } catch(IOException e) {
32 | e.printStackTrace();
33 | }
34 | }
35 | }
36 |
37 | protected String getHelpMessage() {
38 | return "opens the folder\n"
39 | + "'" + Game.USERDATA_DIR_NAME + "'\n"
40 | + "in the file explorer";
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/HelpCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.shell.Shell;
4 |
5 | public class HelpCommand extends ShellCommand {
6 |
7 | public HelpCommand() {
8 | super("help");
9 | }
10 |
11 | public void run(String[] args) {
12 | if(args.length > 0) {
13 | String commandName = args[0];
14 |
15 | ShellCommand command = ShellCommand.findCommand(commandName);
16 | if(command == null) {
17 | Shell.write("help: command not found\n\n");
18 | } else {
19 | Shell.write(command.getHelpMessage() + "\n\n");
20 | }
21 | } else {
22 | Shell.write("run: runs game\n");
23 | Shell.write("edit: opens editor\n");
24 | Shell.write("pack: creates cartridge\n");
25 | Shell.write("setup: creates game files\n");
26 | Shell.write("cls: clears shell\n");
27 | Shell.write("ver: prints version\n");
28 | Shell.write("help: prints this list\n");
29 | Shell.write("mode: changes console mode\n");
30 | Shell.write("files: opens game folder\n");
31 | Shell.write("log: opens log file\n");
32 | Shell.write("\n");
33 | }
34 | }
35 |
36 | protected String getHelpMessage() {
37 | return "'help'\n"
38 | + "prints a list of commands\n"
39 | + "'help '\n"
40 | + "prints an help message for\n"
41 | + "the given command";
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/LogCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import java.awt.Desktop;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import vulc.luag.Console;
8 |
9 | public class LogCommand extends ShellCommand {
10 |
11 | public LogCommand() {
12 | super("log");
13 | isDevelopersOnly = true;
14 | }
15 |
16 | protected void run(String[] args) {
17 | // if(args.length < 1) {
18 | // openFile();
19 | // } else {
20 | // String level = args[0];
21 | // if(level.equals("all")) {
22 | // Console.LOGGER.setLevel(Level.ALL);
23 | // Shell.write("switching to\n"
24 | // + "'all' level\n\n");
25 | // } else if(level.equals("severe")) {
26 | // Console.LOGGER.setLevel(Level.SEVERE);
27 | // Shell.write("switching to\n"
28 | // + "'severe' level\n\n");
29 | // } else {
30 | // Shell.write("Error:\n"
31 | // + "unrecognized level\n"
32 | // + "try 'all' or 'severe'\n\n");
33 | // }
34 | // }
35 |
36 | openFile();
37 | }
38 |
39 | private void openFile() {
40 | if(Desktop.isDesktopSupported()) {
41 | Desktop desktop = Desktop.getDesktop();
42 |
43 | File file = new File(Console.logFile);
44 | if(!file.isFile()) {
45 | Console.die("Error:\n"
46 | + "log file not found");
47 | return;
48 | }
49 |
50 | try {
51 | desktop.open(file);
52 | } catch(IOException e) {
53 | e.printStackTrace();
54 | }
55 | }
56 | }
57 |
58 | // protected String getHelpMessage() {
59 | // return "'log'\n"
60 | // + "opens log file\n"
61 | // + "'log '\n"
62 | // + "changes log level\n"
63 | // + "'all': info and errors\n"
64 | // + "'severe': errors";
65 | // }
66 |
67 | protected String getHelpMessage() {
68 | return "opens log file in\n"
69 | + "the default editor";
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/ModeCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.Console.Mode;
5 | import vulc.luag.shell.Shell;
6 |
7 | public class ModeCommand extends ShellCommand {
8 |
9 | public ModeCommand() {
10 | super("mode");
11 | }
12 |
13 | public void run(String[] args) {
14 | if(args.length < 1) {
15 | Shell.write("current mode:\n");
16 | if(Console.mode == Mode.DEVELOPER) {
17 | Shell.write("developer");
18 | } else {
19 | Shell.write("user");
20 | }
21 | Shell.write("\n\n");
22 | return;
23 | }
24 |
25 | String mode = args[0];
26 | if(mode.equals("d") || mode.equals("developer")) {
27 | Console.mode = Mode.DEVELOPER;
28 | Shell.write("switching to\n"
29 | + "developer mode\n\n");
30 | } else if(mode.equals("u") || mode.equals("user")) {
31 | Console.mode = Mode.USER_SHELL;
32 | Shell.write("switching to\n"
33 | + "user mode\n\n");
34 | } else {
35 | Console.die("Error:\n"
36 | + "unrecognized mode\n"
37 | + "try 'd' or 'u'");
38 | }
39 | }
40 |
41 | protected String getHelpMessage() {
42 | return "'mode '\n"
43 | + "changes the console mode\n"
44 | + "'d' is developer\n"
45 | + "'u' is user";
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/PackCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.OutputStreamWriter;
12 | import java.util.zip.ZipEntry;
13 | import java.util.zip.ZipOutputStream;
14 |
15 | import com.google.gson.stream.JsonWriter;
16 |
17 | import vulc.luag.Console;
18 | import vulc.luag.game.Game;
19 | import vulc.luag.game.cartridge.Cartridge;
20 | import vulc.luag.game.interfaces.LuaInterface;
21 |
22 | public class PackCommand extends ShellCommand {
23 |
24 | public PackCommand() {
25 | super("pack");
26 | isDevelopersOnly = true;
27 | }
28 |
29 | public void run(String[] args) {
30 | if(args.length < 1) {
31 | Console.die("Error: missing arguments\n"
32 | + "pack [cartridge-name]");
33 | return;
34 | }
35 |
36 | File consoleUserdata = new File(Game.USERDATA_DIR);
37 | if(!consoleUserdata.isDirectory()) {
38 | Console.die("Error:\n"
39 | + "'" + Game.USERDATA_DIR_NAME + "'\n"
40 | + "folder not found");
41 | return;
42 | }
43 |
44 | File cartridge = new File(Console.rootDirectory + args[0] + "." + Cartridge.EXTENSION);
45 | if(cartridge.exists()) {
46 | Console.die("Error:\n"
47 | + "'" + cartridge + "'\n"
48 | + "file already exists");
49 | return;
50 | }
51 |
52 | synchronized(Console.DONT_STOP_LOCK) {
53 | try {
54 | ZipOutputStream out = null;
55 | boolean error = false;
56 | try {
57 | out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(cartridge)));
58 | cartridge.createNewFile();
59 |
60 | if(!cartridge.exists()) error = true;
61 | } catch(FileNotFoundException e) {
62 | error = true;
63 | }
64 | if(error) {
65 | Console.die("Error:\n"
66 | + "could not\n"
67 | + "create cartridge");
68 | return;
69 | }
70 |
71 | // add files inside 'console-userdata'
72 | File[] files = new File(Game.USERDATA_DIR).listFiles();
73 | for(File f : files) {
74 | addToZip(out, "", f);
75 | }
76 |
77 | // add .cartridge-info file
78 | ZipEntry infoFile = new ZipEntry(Game.CARTRIDGE_INFO_NAME);
79 | out.putNextEntry(infoFile);
80 | {
81 | JsonWriter writer = new JsonWriter(new OutputStreamWriter(out));
82 | writer.beginObject();
83 | writer.name("console-version").value(Console.VERSION);
84 | writer.name("interface-version").value(LuaInterface.DEFAULT_MAJOR_VERSION
85 | + "."
86 | + LuaInterface.minorVersion(LuaInterface.DEFAULT_MAJOR_VERSION));
87 | writer.endObject();
88 |
89 | writer.flush();
90 | }
91 | out.closeEntry();
92 |
93 | out.close();
94 | } catch(IOException e) {
95 | e.printStackTrace();
96 | }
97 | }
98 | }
99 |
100 | private void addToZip(ZipOutputStream zip, String folder, File file) throws IOException {
101 | if(file.isFile()) {
102 | ZipEntry entry = new ZipEntry(folder + file.getName());
103 | zip.putNextEntry(entry);
104 |
105 | InputStream in = new BufferedInputStream(new FileInputStream(file));
106 | byte[] dataBuffer = new byte[1024];
107 | int lengthRead;
108 |
109 | while((lengthRead = in.read(dataBuffer)) >= 0) {
110 | zip.write(dataBuffer, 0, lengthRead);
111 | zip.flush();
112 | }
113 | in.close();
114 |
115 | zip.closeEntry();
116 | } else if(file.isDirectory()) {
117 | File[] files = file.listFiles();
118 | for(File f : files) {
119 | addToZip(zip, folder + file.getName() + "/", f);
120 | }
121 | }
122 | }
123 |
124 | protected String getHelpMessage() {
125 | return "'pack '\n"
126 | + "creates a cartridge";
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/RunCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.Console.Mode;
5 | import vulc.luag.game.cartridge.Cartridge;
6 | import vulc.luag.gfx.panel.GamePanel;
7 |
8 | public class RunCommand extends ShellCommand {
9 |
10 | public RunCommand() {
11 | super("run");
12 | }
13 |
14 | public void run(String[] args) {
15 | if(args.length >= 1) {
16 | Console.cartridge = Console.rootDirectory + args[0] + "." + Cartridge.EXTENSION;
17 | } else {
18 | Console.cartridge = null;
19 |
20 | if(Console.mode == Mode.USER_SHELL) {
21 | Console.die("Error:\n"
22 | + "insert cartridge name");
23 | return;
24 | }
25 | }
26 | Console.switchToPanel(new GamePanel());
27 | }
28 |
29 | protected String getHelpMessage() {
30 | if(Console.mode == Mode.DEVELOPER) {
31 | return "'run'\n"
32 | + "runs the developed game\n"
33 | + "'run '\n"
34 | + "runs the cartridge";
35 | } else {
36 | return "'run '\n"
37 | + "runs the cartridge";
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/SetupCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.util.zip.ZipEntry;
10 | import java.util.zip.ZipInputStream;
11 |
12 | import vulc.luag.Console;
13 | import vulc.luag.game.Game;
14 |
15 | public class SetupCommand extends ShellCommand {
16 |
17 | private static final String TEMPLATE_FILE = "/res/templates/template.zip";
18 |
19 | public SetupCommand() {
20 | super("setup");
21 | isDevelopersOnly = true;
22 | }
23 |
24 | public void run(String[] args) {
25 | File folder = new File(Game.USERDATA_DIR);
26 | if(folder.exists()) {
27 | Console.die("Error:\n"
28 | + "'" + Game.USERDATA_DIR_NAME + "'\n"
29 | + "already exists");
30 | return;
31 | }
32 |
33 | synchronized(Console.DONT_STOP_LOCK) {
34 | try {
35 | new File(Game.USERDATA_DIR).mkdir();
36 |
37 | ZipInputStream template =
38 | new ZipInputStream(new BufferedInputStream(SetupCommand.class.getResourceAsStream(TEMPLATE_FILE)));
39 |
40 | ZipEntry entry;
41 | byte[] buffer = new byte[1024];
42 |
43 | while((entry = template.getNextEntry()) != null) {
44 | File file = new File(Game.USERDATA_DIR + "/" + entry.getName());
45 | if(entry.isDirectory()) {
46 | file.mkdirs();
47 | } else {
48 | OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
49 |
50 | int readLength;
51 | while((readLength = template.read(buffer)) > 0) {
52 | out.write(buffer, 0, readLength);
53 | }
54 | out.close();
55 | }
56 | }
57 | template.closeEntry();
58 | template.close();
59 | } catch(IOException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 | }
64 |
65 | protected String getHelpMessage() {
66 | return "creates blank game files";
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/ShellCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import java.util.Arrays;
4 |
5 | import vulc.luag.Console;
6 | import vulc.luag.Console.Mode;
7 |
8 | public abstract class ShellCommand {
9 |
10 | private static final ShellCommand[] COMMAND_LIST = {
11 | new RunCommand(),
12 | new EditCommand(),
13 | new PackCommand(),
14 | new SetupCommand(),
15 | new ClsCommand(),
16 | new VerCommand(),
17 | new HelpCommand(),
18 | new ModeCommand(),
19 | new FilesCommand(),
20 | new LogCommand(),
21 | new ExitCommand()
22 | };
23 |
24 | private final String[] names;
25 | protected boolean isDevelopersOnly = false;
26 |
27 | public ShellCommand(String... names) {
28 | this.names = names;
29 | }
30 |
31 | protected abstract void run(String[] args);
32 |
33 | protected String getHelpMessage() {
34 | return "this command has no\n"
35 | + "'help' message";
36 | }
37 |
38 | // returns true if could find a command, else false
39 | public static boolean execute(String line) {
40 | Console.LOGGER.info("Shell execute: '" + line + "'");
41 |
42 | String[] splittedLine = line.split(" ");
43 |
44 | String name = splittedLine[0];
45 | String[] args = Arrays.copyOfRange(splittedLine, 1, splittedLine.length);
46 |
47 | ShellCommand command = findCommand(name);
48 | if(command != null) {
49 | if(command.isDevelopersOnly && Console.mode != Mode.DEVELOPER) {
50 | Console.die("Error:\n"
51 | + "only developers can\n"
52 | + "use this command");
53 | } else {
54 | command.run(args);
55 | }
56 | return true;
57 | }
58 | return false;
59 | }
60 |
61 | protected static ShellCommand findCommand(String name) {
62 | for(ShellCommand command : COMMAND_LIST) {
63 | for(int i = 0; i < command.names.length; i++) {
64 | if(name.equalsIgnoreCase(command.names[i])) return command;
65 | }
66 | }
67 | return null;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/vulc/luag/shell/command/VerCommand.java:
--------------------------------------------------------------------------------
1 | package vulc.luag.shell.command;
2 |
3 | import vulc.luag.Console;
4 | import vulc.luag.shell.Shell;
5 |
6 | public class VerCommand extends ShellCommand {
7 |
8 | public VerCommand() {
9 | super("ver", "version");
10 | }
11 |
12 | public void run(String[] args) {
13 | Shell.write(Console.VERSION + " - By Vulcalien\n\n");
14 | }
15 |
16 | protected String getHelpMessage() {
17 | return "prints version and author";
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------