Do not use backslash-b to select backspaces.
[mp-5.x.git] / mp_toys.mpsl
blob36c71a4a7c6b027af59e3fe11ae8f37d493bbd0a
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Useless things.
8     Copyright (C) 1991-2012 Angel Ortega <angel@triptico.com>
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     as published by the Free Software Foundation; either version 2
13     of the License, or (at your option) any later version.
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24     http://www.triptico.com
28 /** editor actions **/
30 mp.actions['pipes'] =   sub (d) {
31     mp.pipes();
34 /** action descriptions **/
36 mp.actdesc['pipes'] = LL("Play \"Pipes\"");
38 /** code **/
40 sub mp.maze(doc, keycode)
42         local tx = mp.window.tx;
43         local ty = mp.window.ty;
45         if (doc == NULL)
46                 doc = mp.open('<maze>');
48         local maze = doc.maze;
50         if (maze == NULL || maze.tx != tx || maze.ty != ty) {
51                 /* new or changed: rebuild everything */
52                 maze = {};
53                 maze.tx = tx;
54                 maze.ty = ty;
55                 doc.maze = maze;
57                 /* ensure odd size */
58                 if (!(tx & 1))
59                         tx--;
60                 if (!(ty & 1))
61                         ty--;
63                 /* init */
64                 maze.map = map(
65             [1 .. ty],
66             sub {
67                 map(
68                     [1 .. tx],
69                     sub { '#'; }
70                 );
71             }
72         );
74                 /* build */
75                 local x = 1;
76                 local y = 1;
77                 local stack = [];
79                 while (1) {
80                         local d = [];
82                         /* clear */
83                         maze.map[y][x] = ' ';
85                         foreach (t, [[0, -1], [1, 0], [0, 1], [-1, 0]]) {
86                                 /* can space be opened? */
87                                 local ny = y + t[0] * 2;
88                                 local nx = x + t[1] * 2;
90                                 if (nx > 0 && ny > 0 && maze.map[ny][nx] eq '#')
91                                         push(d, t);
92                         }
94                         if (size(d)) {
95                                 /* more than one way? stack this position */
96                                 if (size(d) > 1)
97                                         push(stack, [y, x]);
99                                 /* pick one direction at random and move there */
100                                 local m = d[random(size(d))];
102                                 y += m[0];
103                                 x += m[1];
105                                 maze.map[y][x] = ' ';
107                                 y += m[0];
108                                 x += m[1];
109                         }
110                         else {
111                                 /* no way from here: pop previous position */
112                                 if ((d = pop(stack)) == NULL)
113                                         break;
115                                 y = d[0];
116                                 x = d[1];
117                         }
118                 }
120                 maze.x = 1 + random(tx / 2) * 2;
121                 maze.y = 1 + random(ty / 2) * 2;
123                 maze.map[maze.y][maze.x] = '@';
125                 x = 1 + random(tx / 2) * 2;
126                 y = 1 + random(ty / 2) * 2;
128                 maze.map[y][x] = 'X';
130                 doc.keypress = sub(d, k) { mp.maze(d, k); };
132                 doc.paint = sub(d) { map(d.maze.map, sub(e) { [8, join(e)];}); };
133         }
135         local x = maze.x;
136         local y = maze.y;
138         maze.map[y][x] = ' ';
140         if (keycode eq 'cursor-up')
141                 y--;
142         if (keycode eq 'cursor-down')
143                 y++;
144         if (keycode eq 'cursor-left')
145                 x--;
146         if (keycode eq 'cursor-right')
147                 x++;
149         if (maze.map[y][x] eq 'X') {
150                 mp.alert(L("You won!"));
151                 doc.maze = NULL;
152                 return mp.maze(doc);
153         }
155         if (maze.map[y][x] eq ' ') {
156                 maze.x = x;
157                 maze.y = y;
158         }
160         maze.map[maze.y][maze.x] = '@';
162     mp.undo(doc);
164         return doc;
168 sub mp.pipes(doc, keycode)
170     local tx = mp.window.tx;
171     local ty = mp.window.ty;
173     if (doc == NULL)
174         doc = mp.open('<pipes>');
176     local pipes = doc.pipes;
178     if (pipes == NULL || pipes.you_won || pipes.tx != tx || pipes.ty != ty) {
179         local wx = int((tx - 2) / 3);
180         local wy = int(((ty - 1) / 3) - 1);
182         pipes = {
183             x:      0,
184             y:      1,
185             tx:     tx,
186             ty:     ty,
187             wx:     wx,
188             wy:     wy,
189             sx:     random(wx),
190             dir:    [[0, -1], [1, 0], [0, 1], [-1, 0]],
191             pieces: [
192                 {
193                     shape:  [' # ', ' ##', '   '],
194                     out:    [-1, -1, 1, 0],
195                     next:   1
196                 },
197                 {
198                     shape:  ['   ', ' ##', ' # '],
199                     out:    [1, -1, -1, 2],
200                     next:   2
201                 },
202                 {
203                     shape:  ['   ', '## ', ' # '],
204                     out:    [3, 2, -1, -1],
205                     next:   3
206                 },
207                 {
208                     shape:  [' # ', '## ', '   '],
209                     out:    [-1, 0, 3, -1],
210                     next:   0
211                 },
212                 {
213                     shape:  [' # ', ' # ', ' # '],
214                     out:    [0, -1, 2, -1],
215                     next:   5
216                 },
217                 {
218                     shape:  ['   ', '###', '   '],
219                     out:    [-1, 1, -1, 3],
220                     next:   4
221                 },
222                 { /* blank */
223                     shape:  ['   ', '   ', '   '],
224                     out:    [-1, -1, -1, -1],
225                     next:   6
226                 },
227                 { /* entry pipe */
228                     shape:  ['| |', '\ /', ' # '],
229                     out:    [-1, -1, 2, -1],
230                     next:   7
231                 },
232                 { /* out pipe */
233                     shape:  [' # ', ' # ', '/ \'],
234                     out:    [-1, -1, -1000, -1],
235                     next:   8
236                 }
237             ]
238         };
240         pipes.map = map([1 .. wy - 1],
241             sub {map([1 .. wx], sub { random(size(pipes.pieces) - 3); });}
242         );
244         /* add first line */
245         ins(pipes.map, map([1 .. wx], sub { 6; }), 0);
246         pipes.map[0][pipes.sx] = 7;
248         /* add last line */
249         push(pipes.map, map([1 .. wx], sub { 6; }));
250         pipes.map[wy][5] = 8;
251         pipes.map[wy][wx - 5] = 8;
253         doc.pipes = pipes;
255         /* handlers */
256         doc.keypress    = sub (d, k) { mp.pipes(d, k); };
258         doc.paint       = sub (d) {
259             local out = [];
260             local pipes = d.pipes;
262             foreach (n, [0 .. pipes.wy]) {
263                 local l0 = [];
264                 local l1 = [];
265                 local l2 = [];
267                 foreach (m, [0 .. (pipes.wx - 1)]) {
268                     local p = pipes.map[n][m];
269                     local s = pipes.pieces[p].shape;
270                     local c;
272                     if (n == pipes.y && m == pipes.x)
273                         c = mp.colors.cursor.attr;
274                     else
275                         c = pipes.attr[n][m] || mp.colors.normal.attr;
277                     push(l0, c, s[0]);
278                     push(l1, c, s[1]);
279                     push(l2, c, s[2]);
280                 }
282                 push(out, l0, l1, l2);
283             }
285             if (pipes.you_won) {
286                 out[0] = [
287                     mp.colors.cursor.attr,
288                     L("You won! Press any key.")
289                 ];
290             }
292             return out;
293         };
294     }
296         local x = pipes.x;
297         local y = pipes.y;
299         if (keycode eq 'cursor-up' && y > 1)
300                 y--;
301         if (keycode eq 'cursor-down'&& y < pipes.wy - 1)
302                 y++;
303         if (keycode eq 'cursor-left' && x > 0)
304                 x--;
305         if (keycode eq 'cursor-right' && x < pipes.wx - 1)
306                 x++;
307     if (keycode eq 'enter') {
308         local n = pipes.map[y][x];
310         pipes.map[y][x] = pipes.pieces[n].next;
311     }
313     pipes.x = x;
314     pipes.y = y;
316     /* reset attributes */
317     pipes.attr = map([0 .. pipes.wy], sub { [];});
319     /* the water input is blue */
320     pipes.attr[0][pipes.sx] = mp.colors.quotes.attr;
322     /* calculate the path */
323     local px = pipes.sx;
324     local py = 0;
325     local c = 2; /* downwards */
326     local p;
328     /* while there is a valid path */
329     while ((p = pipes.pieces[pipes.map[py][px]]) && (c = p.out[c]) >= 0) {
330         /* mark as valid path */
331         pipes.attr[py][px] = mp.colors.quotes.attr;
333         /* move in new direction */
334         px += pipes.dir[c][0];
335         py += pipes.dir[c][1];
336     }
338     if (c == -1000) {
339         pipes.attr[py][px] = mp.colors.quotes.attr;
340         pipes.you_won = 1;
341     }
343     mp.undo(doc);
345     return doc;