summary refs log tree commit diff stats
path: root/src/com/fourisland
diff options
context:
space:
mode:
authorStarla Insigna <hatkirby@fourisland.com>2009-03-05 20:54:17 -0500
committerStarla Insigna <hatkirby@fourisland.com>2009-03-05 20:54:17 -0500
commita0f6cd976b8661eb608794ae169185b45b1b0a88 (patch)
treec737e11d81e4ad719ff6a7c17c38eb360add50e3 /src/com/fourisland
parent82e91f3b85917f456214c121daa97ba65c7cce2a (diff)
downloadfourpuzzle-a0f6cd976b8661eb608794ae169185b45b1b0a88.tar.gz
fourpuzzle-a0f6cd976b8661eb608794ae169185b45b1b0a88.tar.bz2
fourpuzzle-a0f6cd976b8661eb608794ae169185b45b1b0a88.zip
Engine: Created Message Escapes
Rewrote MessageWindow to render text through another class called TextRenderer, which takes settings and parses the text with its message escapes. The text-color-setting escape works perfectly but the pause escape doesn't. It works pretty well, except for some reason, if the escape is directly next to some text on the left, it won't be parsed. Also, the pause escape was implemented as \P rather than \| because | is a special character .in regular expressions.

The variable-displaying escape was not added for two reasons: First of all, a dynamically introduced variable would mess up the generated layout and the text would not wrap correctly. Secondly, a much easier/better way of including a variable in a message than message escapes exists: Using string concatenation when writing the DisplayMessage() call. As FourPuzzle is a programming library, it is much more powerful than RM2K and clients need not resort to strange hacks such as message escapes to include variables in messages. Clients can include whatever dynamic data they wish in messages, rather than some predefined stuff RM2K provides.

A small bug was discovered in PauseTimer that made it wait for it's underlying Interval to elapse before it could elapse, even if it had zero ticks remaining. This has been fixed.

Closes #16
Diffstat (limited to 'src/com/fourisland')
-rw-r--r--src/com/fourisland/fourpuzzle/util/PauseTimer.java12
-rwxr-xr-xsrc/com/fourisland/fourpuzzle/window/ChoiceWindow.java2
-rw-r--r--src/com/fourisland/fourpuzzle/window/MessageEscape.java79
-rw-r--r--src/com/fourisland/fourpuzzle/window/MessageWindow.java115
-rwxr-xr-xsrc/com/fourisland/fourpuzzle/window/SystemGraphic.java9
-rw-r--r--src/com/fourisland/fourpuzzle/window/TextRenderer.java306
6 files changed, 420 insertions, 103 deletions
diff --git a/src/com/fourisland/fourpuzzle/util/PauseTimer.java b/src/com/fourisland/fourpuzzle/util/PauseTimer.java index 7d66d1a..f26f105 100644 --- a/src/com/fourisland/fourpuzzle/util/PauseTimer.java +++ b/src/com/fourisland/fourpuzzle/util/PauseTimer.java
@@ -29,12 +29,12 @@ public class PauseTimer {
29 29
30 if (in.isElapsed()) 30 if (in.isElapsed())
31 { 31 {
32 if (ticks == 0) 32 ticks--;
33 { 33 }
34 return true; 34
35 } else { 35 if (ticks <= 0)
36 ticks--; 36 {
37 } 37 return true;
38 } 38 }
39 39
40 return false; 40 return false;
diff --git a/src/com/fourisland/fourpuzzle/window/ChoiceWindow.java b/src/com/fourisland/fourpuzzle/window/ChoiceWindow.java index 4926a6d..90f2d96 100755 --- a/src/com/fourisland/fourpuzzle/window/ChoiceWindow.java +++ b/src/com/fourisland/fourpuzzle/window/ChoiceWindow.java
@@ -79,7 +79,7 @@ public class ChoiceWindow implements Renderable {
79 g2.drawImage(Window.Selector.getImage(fw-Window.Selector.getLeftX(), fh-Window.Selector.getTopY()), tx-SPACER, ty-fh-SPACER, null); 79 g2.drawImage(Window.Selector.getImage(fw-Window.Selector.getLeftX(), fh-Window.Selector.getTopY()), tx-SPACER, ty-fh-SPACER, null);
80 } 80 }
81 81
82 g2.setPaint(new TexturePaint(SystemGraphic.getTextColor(), new Rectangle(tx, ty, fw, fh))); 82 g2.setPaint(new TexturePaint(SystemGraphic.getTextColor(0), new Rectangle(tx, ty, fw, fh)));
83 g2.drawString(choice, tx, ty); 83 g2.drawString(choice, tx, ty);
84 84
85 ty+=(SPACER+fh); 85 ty+=(SPACER+fh);
diff --git a/src/com/fourisland/fourpuzzle/window/MessageEscape.java b/src/com/fourisland/fourpuzzle/window/MessageEscape.java new file mode 100644 index 0000000..2ae55b2 --- /dev/null +++ b/src/com/fourisland/fourpuzzle/window/MessageEscape.java
@@ -0,0 +1,79 @@
1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5
6package com.fourisland.fourpuzzle.window;
7
8import java.util.regex.MatchResult;
9import java.util.regex.Matcher;
10import java.util.regex.Pattern;
11
12
13/**
14 *
15 * @author hatkirby
16 */
17public enum MessageEscape
18{
19 Color("\\\\C\\[(\\d+)\\]"),
20 Pause("\\\\P");
21
22 private Pattern pattern;
23 private MessageEscape(String pattern)
24 {
25 this.pattern = Pattern.compile(pattern);
26 }
27
28 public static String removeEscapes(String message)
29 {
30 for (MessageEscape escape : values())
31 {
32 message = escape.pattern.matcher(message).replaceAll("");
33 }
34
35 return message;
36 }
37
38 public boolean match(String substring)
39 {
40 Matcher m = pattern.matcher(substring);
41
42 return (m.lookingAt() && (m.start() == 0));
43 }
44
45 public String removeEscape(String message)
46 {
47 return pattern.matcher(message).replaceFirst("");
48 }
49
50 MessageEscapePair getMatch(String substring)
51 {
52 Matcher m = pattern.matcher(substring);
53 m.lookingAt();
54
55 return new MessageEscapePair(this, m.toMatchResult());
56 }
57}
58
59class MessageEscapePair
60{
61 MessageEscape escape;
62 MatchResult match;
63
64 public MessageEscapePair(MessageEscape escape, MatchResult match)
65 {
66 this.escape = escape;
67 this.match = match;
68 }
69
70 public MessageEscape getMessageEscape()
71 {
72 return escape;
73 }
74
75 public MatchResult getMatchResult()
76 {
77 return match;
78 }
79} \ No newline at end of file
diff --git a/src/com/fourisland/fourpuzzle/window/MessageWindow.java b/src/com/fourisland/fourpuzzle/window/MessageWindow.java index dab67d1..709704a 100644 --- a/src/com/fourisland/fourpuzzle/window/MessageWindow.java +++ b/src/com/fourisland/fourpuzzle/window/MessageWindow.java
@@ -14,11 +14,7 @@ import com.fourisland.fourpuzzle.util.Inputable;
14import com.fourisland.fourpuzzle.util.Interval; 14import com.fourisland.fourpuzzle.util.Interval;
15import com.fourisland.fourpuzzle.util.Renderable; 15import com.fourisland.fourpuzzle.util.Renderable;
16import java.awt.Graphics2D; 16import java.awt.Graphics2D;
17import java.awt.Rectangle;
18import java.awt.TexturePaint;
19import java.awt.image.BufferedImage; 17import java.awt.image.BufferedImage;
20import java.util.ArrayList;
21import java.util.List;
22import java.util.concurrent.CountDownLatch; 18import java.util.concurrent.CountDownLatch;
23 19
24/** 20/**
@@ -30,10 +26,9 @@ public class MessageWindow implements Renderable {
30 private static final int SPACER = 4; 26 private static final int SPACER = 4;
31 private static final int HEIGHT = (4*(Display.getFontMetrics().getHeight()+SPACER)); 27 private static final int HEIGHT = (4*(Display.getFontMetrics().getHeight()+SPACER));
32 28
33 private volatile List<String> messages; 29 TextRenderer tr;
34 int width; 30 int width;
35 BufferedImage cacheBase; 31 BufferedImage cacheBase;
36 int num = 0;
37 int upTo = 0; 32 int upTo = 0;
38 boolean bounceArrow = false; 33 boolean bounceArrow = false;
39 Interval in = Interval.createTickInterval(4); 34 Interval in = Interval.createTickInterval(4);
@@ -42,7 +37,9 @@ public class MessageWindow implements Renderable {
42 width = Game.WIDTH - Window.Default.getFullWidth(0); 37 width = Game.WIDTH - Window.Default.getFullWidth(0);
43 cacheBase = Window.Default.getImage(width, HEIGHT); 38 cacheBase = Window.Default.getImage(width, HEIGHT);
44 39
45 initalizeMessages(message); 40 tr = new TextRenderer(width);
41 tr.setEscapes(true);
42 tr.initalizeText(message);
46 } 43 }
47 44
48 boolean hasFace = false; 45 boolean hasFace = false;
@@ -55,7 +52,10 @@ public class MessageWindow implements Renderable {
55 this.face = FaceSet.getFaceSet(faceSet).getImage(face); 52 this.face = FaceSet.getFaceSet(faceSet).getImage(face);
56 hasFace = true; 53 hasFace = true;
57 54
58 initalizeMessages(message); 55 tr = new TextRenderer(width);
56 tr.setEscapes(true);
57 tr.setIndent(48 + (SPACER*2));
58 tr.initalizeText(message);
59 } 59 }
60 60
61 private static void displayMessage(final MessageWindow mw) throws InterruptedException 61 private static void displayMessage(final MessageWindow mw) throws InterruptedException
@@ -101,96 +101,24 @@ public class MessageWindow implements Renderable {
101 displayMessage(new MessageWindow(message, faceSet, face)); 101 displayMessage(new MessageWindow(message, faceSet, face));
102 } 102 }
103 103
104 private void initalizeMessages(String message)
105 {
106 messages = new ArrayList<String>();
107
108 int length = width - SPACER;
109 if (hasFace)
110 {
111 length -= (48 + (SPACER*3));
112 }
113
114 String temp = message;
115 int len = 0;
116 while (!temp.isEmpty())
117 {
118 while ((Display.getFontMetrics().stringWidth(temp.substring(0, len)) < length) && (len < temp.length()))
119 {
120 len++;
121 }
122
123 if (len != temp.length())
124 {
125 while ((!temp.substring(len, len+1).equals(" ")) && (len > 0))
126 {
127 len--;
128 }
129 }
130
131 messages.add(temp.substring(0, len));
132
133 if (len != temp.length())
134 {
135 temp = temp.substring(len+1);
136 } else {
137 temp = "";
138 }
139
140 len = 0;
141 }
142
143 setLength();
144 }
145
146 private void setLength()
147 {
148 num = 0;
149
150 for (int i=0;i<Math.min(messages.size(),4);i++)
151 {
152 num += messages.get(i).length();
153 }
154 }
155
156 public void render(Graphics2D g2) 104 public void render(Graphics2D g2)
157 { 105 {
158 int y = MessageWindowLocation.Bottom.getY(); 106 int y = MessageWindowLocation.Bottom.getY();
159
160 Display.setFont(g2);
161 107
162 g2.drawImage(cacheBase, 0, y, null); 108 g2.drawImage(cacheBase, 0, y, null);
163 109
164 int fh = g2.getFontMetrics().getHeight(); 110 int fh = g2.getFontMetrics().getHeight();
165 int tx = Window.Default.getLeftX();
166 int ty = Window.Default.getTopY()+fh-(SPACER/2)+y; 111 int ty = Window.Default.getTopY()+fh-(SPACER/2)+y;
167 int msgs = Math.min(messages.size(), 4);
168 int toPrint = upTo;
169 112
170 if (hasFace) 113 if (hasFace)
171 { 114 {
172 g2.drawImage(face, tx+SPACER, ty-fh+SPACER, null); 115 g2.drawImage(face, Window.Default.getLeftX()+SPACER, ty-fh+SPACER, null);
173
174 tx += 48 + (SPACER*2);
175 } 116 }
176 117
177 for (int i=0;i<msgs;i++) 118 g2.drawImage(tr.render(upTo), Window.Default.getLeftX(), Window.Default.getTopY()+y, null);
178 {
179 String message = messages.get(i);
180 int fw = g2.getFontMetrics().stringWidth(message);
181
182 g2.setPaint(new TexturePaint(SystemGraphic.getTextColor(), new Rectangle(tx, ty, fw, fh)));
183 g2.drawString(message.substring(0, Math.min(toPrint, message.length())), tx, ty);
184
185 ty+=(SPACER+fh);
186
187 toPrint -= Math.min(toPrint, message.length());
188 }
189 119
190 if (upTo < num) 120 if (tr.isCascadingDone())
191 { 121 {
192 upTo+=3;
193 } else {
194 g2.drawImage(SystemGraphic.getDownArrow(), (Window.Default.getFullWidth(width)/2)-5, y+HEIGHT+SPACER+(bounceArrow ? 1 : 0), null); 122 g2.drawImage(SystemGraphic.getDownArrow(), (Window.Default.getFullWidth(width)/2)-5, y+HEIGHT+SPACER+(bounceArrow ? 1 : 0), null);
195 123
196 if (in.isElapsed()) 124 if (in.isElapsed())
@@ -202,20 +130,19 @@ public class MessageWindow implements Renderable {
202 130
203 private synchronized boolean pushEnter() 131 private synchronized boolean pushEnter()
204 { 132 {
205 if (upTo >= num) 133 if (tr.isCascadingDone())
206 { 134 {
207 int msgs = messages.size(); 135 int msgs = tr.numLines();
208 for (int i=0;i<Math.min(4, msgs);i++) 136 if (upTo >= (msgs-4))
209 { 137 {
210 messages.remove(0);
211 }
212
213 if (messages.size() > 0)
214 {
215 upTo = 0;
216 setLength();
217 } else {
218 return true; 138 return true;
139 } else {
140 upTo += 4;
141
142 if (upTo > msgs)
143 {
144 upTo = msgs;
145 }
219 } 146 }
220 } 147 }
221 148
diff --git a/src/com/fourisland/fourpuzzle/window/SystemGraphic.java b/src/com/fourisland/fourpuzzle/window/SystemGraphic.java index 75e2b45..aa0b593 100755 --- a/src/com/fourisland/fourpuzzle/window/SystemGraphic.java +++ b/src/com/fourisland/fourpuzzle/window/SystemGraphic.java
@@ -64,14 +64,19 @@ public class SystemGraphic {
64 return systemGraphic.getSubimage(sca.x, sca.y, sca.width, sca.height); 64 return systemGraphic.getSubimage(sca.x, sca.y, sca.width, sca.height);
65 } 65 }
66 66
67 public static BufferedImage getTextColor() 67 public static BufferedImage getTextColor(int color)
68 { 68 {
69 if (systemGraphic == null) 69 if (systemGraphic == null)
70 { 70 {
71 initalize(); 71 initalize();
72 } 72 }
73 73
74 return systemGraphic.getSubimage(0, 48, 16, 16); 74 if (color < 10)
75 {
76 return systemGraphic.getSubimage(color*16, 48, 16, 16);
77 } else {
78 return systemGraphic.getSubimage(color*16, 64, 16, 16);
79 }
75 } 80 }
76 81
77 public static BufferedImage getUpArrow() 82 public static BufferedImage getUpArrow()
diff --git a/src/com/fourisland/fourpuzzle/window/TextRenderer.java b/src/com/fourisland/fourpuzzle/window/TextRenderer.java new file mode 100644 index 0000000..f114c4d --- /dev/null +++ b/src/com/fourisland/fourpuzzle/window/TextRenderer.java
@@ -0,0 +1,306 @@
1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5
6package com.fourisland.fourpuzzle.window;
7
8import com.fourisland.fourpuzzle.Display;
9import com.fourisland.fourpuzzle.Game;
10import com.fourisland.fourpuzzle.util.PauseTimer;
11import java.awt.Graphics2D;
12import java.awt.Rectangle;
13import java.awt.TexturePaint;
14import java.awt.image.BufferedImage;
15import java.util.ArrayList;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19import java.util.Vector;
20
21/**
22 *
23 * @author hatkirby
24 */
25public class TextRenderer {
26
27 private static final int SPACER = 4;
28
29 private boolean initalized = false;
30 private int width;
31 private List<LineOfText> messages = new ArrayList<LineOfText>();
32
33 public TextRenderer(int width)
34 {
35 this.width = width;
36 }
37
38 private boolean useEscapes = false;
39 public void setEscapes(boolean use)
40 {
41 if (initalized == true)
42 {
43 throw new IllegalStateException("Already initalized");
44 }
45
46 useEscapes = use;
47 }
48
49 private int indent = 0;
50 public void setIndent(int indent)
51 {
52 if (initalized == true)
53 {
54 throw new IllegalStateException("Already initalized");
55 }
56
57 this.indent = indent;
58 }
59
60 public void initalizeText(String message)
61 {
62 if (initalized == true)
63 {
64 throw new IllegalStateException("Already initalized");
65 }
66
67 int length = width - SPACER - indent;
68 int len = 0;
69 LineOfText temp = new LineOfText(message);
70
71 if (useEscapes)
72 {
73 for (int i=0; i<temp.length(); i++)
74 {
75 if (temp.toString().substring(i, i+1).equals("\\"))
76 {
77 for (MessageEscape escape : MessageEscape.values())
78 {
79 if (escape.match(temp.toString().substring(i)))
80 {
81 temp.addEscape(i, escape.getMatch(temp.toString().substring(i)));
82 temp = new LineOfText(escape.removeEscape(temp.toString()), temp.escapes);
83
84 break;
85 }
86 }
87 }
88 }
89
90 temp = new LineOfText(MessageEscape.removeEscapes(temp.toString()), temp.escapes);
91 }
92
93 while (!temp.toString().isEmpty())
94 {
95 while ((Display.getFontMetrics().stringWidth(temp.toString().substring(0, len)) < length) && (len < temp.length()))
96 {
97 len++;
98 }
99
100 if (len != temp.toString().length())
101 {
102 while ((!temp.toString().substring(len, len+1).equals(" ")) && (len > 0))
103 {
104 len--;
105 }
106 }
107
108 messages.add(temp.part(0, len));
109
110 if (len != temp.length())
111 {
112 temp = temp.part(len+1, temp.length());
113 } else {
114 break;
115 }
116
117 len = 0;
118 }
119
120 initalized = true;
121 }
122
123 int upTo = Integer.MIN_VALUE;
124 int num = 0;
125 int lastStart = Integer.MIN_VALUE+1;
126 PauseTimer pt = new PauseTimer(0);
127 public BufferedImage render(int start)
128 {
129 if (initalized == false)
130 {
131 throw new IllegalStateException("TextRenderer must be initalized prior to rendering");
132 }
133
134 if (lastStart != start)
135 {
136 num = 0;
137 for (int i=start;i<Math.min(messages.size(),start+4);i++)
138 {
139 num += messages.get(i).length();
140 }
141
142 lastStart = start;
143 upTo = 0;
144 }
145
146 BufferedImage temp = Display.createCanvas(width, Game.HEIGHT);
147 Graphics2D g = temp.createGraphics();
148 Display.setFont(g);
149
150 int currentColor = 0;
151
152 int fh = g.getFontMetrics().getHeight();
153 int ty = fh-(SPACER/2);
154 int toPrint = upTo;
155 int end = Math.min(messages.size(), start+4);
156
157 for (int i=start;i<end;i++)
158 {
159 LineOfText message = messages.get(i);
160 int tx = indent;
161 g.setPaint(new TexturePaint(SystemGraphic.getTextColor(currentColor), new Rectangle(0, ty, width, fh)));
162
163 for (int j=0;j<Math.min(toPrint, message.length());j++)
164 {
165 boolean breakout = false;
166 for (MessageEscapePair escape : message.getEscapes(j))
167 {
168 switch (escape.getMessageEscape())
169 {
170 case Color: currentColor = Integer.decode(escape.getMatchResult().group(1));
171 g.setPaint(new TexturePaint(SystemGraphic.getTextColor(currentColor), new Rectangle(0, ty, width, fh)));
172
173 break;
174
175 case Pause: pt.setTimer(10);
176 message.getEscapes(j).remove(escape);
177
178 breakout = true;
179 break;
180 }
181
182 if (breakout)
183 {
184 break;
185 }
186 }
187
188 g.drawString(message.toString().substring(j, j+1), tx, ty);
189
190 tx+=(g.getFontMetrics().stringWidth(message.toString().substring(j, j+1)));
191 }
192
193 ty+=(SPACER+fh);
194
195 toPrint -= Math.min(toPrint, message.length());
196 }
197
198 if (pt.isElapsed() && (upTo < num))
199 {
200 upTo+=3;
201 }
202
203 return temp;
204 }
205
206 public int numLines()
207 {
208 return messages.size();
209 }
210
211 public boolean isCascadingDone()
212 {
213 return (upTo >= num);
214 }
215
216}
217
218class LineOfText implements CharSequence
219{
220 String line;
221 Map<Integer, Vector<MessageEscapePair>> escapes = new HashMap<Integer, Vector<MessageEscapePair>>();
222 public LineOfText(String line)
223 {
224 this.line = line;
225 }
226
227 public LineOfText(String line, Map<Integer, Vector<MessageEscapePair>> escapes)
228 {
229 this.line = line;
230
231 for (int i=0; i<line.length(); i++)
232 {
233 if (escapes.containsKey(i))
234 {
235 for (MessageEscapePair escape : escapes.get(i))
236 {
237 addEscape(i, escape);
238 }
239 }
240 }
241 }
242
243 public void addEscape(int index, MessageEscapePair escape)
244 {
245 if (!escapes.containsKey(index))
246 {
247 escapes.put(index, new Vector<MessageEscapePair>());
248 }
249
250 escapes.get(index).add(escape);
251 }
252
253 public Vector<MessageEscapePair> getEscapes(int index)
254 {
255 if (!escapes.containsKey(index))
256 {
257 return new Vector<MessageEscapePair>();
258 } else {
259 return escapes.get(index);
260 }
261 }
262
263 public LineOfText part(int start, int end)
264 {
265 LineOfText temp = new LineOfText(line.substring(start, end));
266
267 for (int i=start; i<end; i++)
268 {
269 if (escapes.containsKey(i))
270 {
271 for (MessageEscapePair escape : escapes.get(i))
272 {
273 temp.addEscape(i, escape);
274 }
275 }
276 }
277
278 return temp;
279 }
280
281 @Override
282 public String toString()
283 {
284 return line;
285 }
286
287 public void setString(String message)
288 {
289 this.line = message;
290 }
291
292 public int length()
293 {
294 return line.length();
295 }
296
297 public char charAt(int index)
298 {
299 return line.charAt(index);
300 }
301
302 public CharSequence subSequence(int start, int end)
303 {
304 return line.subSequence(start, end);
305 }
306} \ No newline at end of file