1 ! Z-Tornado - Two player weather action game
3 ! Tornado is copyright (C) 2000-2002 Oliver Feiler
4 ! http://www.lionking.org/~kiza/linux/tornado
5 ! Inform version copyright (c) 2003 Sophie Frühling (sfruehling@aon.at)
7 ! This program is free software; you can redistribute it and/or modify
8 ! it under the terms of the GNU General Public License as published by
9 ! the Free Software Foundation; either version 3 of the License, or
10 ! (at your option) any later version.
12 ! This program is distributed in the hope that it will be useful,
13 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ! GNU General Public License for more details.
17 ! You should have received a copy of the GNU General Public License
18 ! along with this program. If not, see <https://www.gnu.org/licenses/>.
25 Global dialog_x; ! dialog box cursor for player input
27 ! Can be switched off in terps where colour doesn't work properly
28 ! (For all I know only useful in Unix Frotz 2.32, where timed input
29 ! doesn't work like it should either)
33 ! 1 if current player, otherwise 0
36 Array player1_name -> 18;
37 Array player2_name -> 18;
38 Global player1_ai = 0;
39 Global player2_ai = 0;
40 Global player1_left = 100;
41 Global player2_left = 100;
42 ! Can handle scores up to 9999999, which should be more than enough
43 Array player1_score -> 7;
44 Array player2_score -> 7;
47 ! Position relative to screen
52 ! How many spaces does the house initially contain?
58 ! 80 x 24 grid, discounting 1 row for statusline and 4 for cloud
59 Array snow_world -> 1520;
60 ! Actual entries of snow_world
64 Array highscore_file string "ZTORNADO.HGH";
65 Array highscore_array -> 220;
67 ! Add degree character to Zcharacter table
68 Zcharacter table + '@{B0}';
73 Include "weather.inf";
76 if (TestTerp() == 0) return;
79 while ((input = Menu()) ~= 'Q') {
84 if (colour) colour = 0;
99 print "----------------------^";
100 print "(A) About Z-Tornado^",
101 "(C) Toggle colour (currently ";
102 if (colour) print "on";
106 "(P) Play Z-Tornado^",
111 'A', 'C', 'I', 'P', 'Q':
117 [ Game; Init(); Tornado(); Bye(); ];
119 Array score_array->7;
120 [ Tornado quitting tmp_score;
127 windspeed = random(11) - 6;
129 player1 = 0; player2 = 1;
130 quitting = Play(player2_ai);
132 player2 = 0; player1 = 1;
133 quitting = Play(player1_ai);
135 if (player1_left <= 0) {
137 - ((CountDestroyed(' ', house2_x, house2_y, 17, 10) - SPACES)*100)/138;
138 CopyArray(score_array, player2_score);
139 Multiply(player2_score, score_array, tmp_score);
142 if (player2_left <= 0) {
144 - ((CountDestroyed(' ', house1_x, house1_y, 17, 10) - SPACES)*100)/138;
145 CopyArray(score_array, player1_score);
146 Multiply(player1_score, score_array, tmp_score);
149 if (quitting) return;
152 AddToHighScore(player1_name, player1_score);
153 AddToHighScore(player2_name, player2_score);
154 if (ContinueGame() == 'N')
159 [ Play ai x input aim destroyed;
161 ! We have a human player
164 input = PlayerChoice();
167 ! lightning: player doesn't have to aim
168 ! tornado: we'll draw the tornado cloud before aiming
169 if (input == 'L' or 'T')
171 if (input == 'H' or 'R' or 'S') {
177 else if (input == 'O')
180 } else { ! The computer chooses
182 input = ErwinChoice(player1_left);
184 input = ErwinChoice(player2_left);
185 aim = ErwinAim(input);
190 x = cloud_x + random(14) - 1;
191 destroyed = DrawWeather(x, windspeed + aim, ':', 2);
193 x = cloud_x + random(14) - 1;
194 destroyed = DrawWeather(x, windspeed + aim, '/', 1);
196 x = cloud_x + random(14) - 1;
197 DrawSnow(x, windspeed + aim);
199 destroyed = DrawLightning(cloud_x - 7 + random(25));
202 if (ai == 0) aim = GetAim();
203 else Pause(2); ! So the player can see the cloud for a while
204 destroyed = DrawTornado(cloud_x, windspeed + aim);
207 - ((CountDestroyed(' ', house2_x, house2_y, 17, 10)
208 + CountSnow(house2_x, house2_y, 17, 10) - SPACES)*100)/138;
210 - ((CountDestroyed(' ', house1_x, house1_y, 17, 10)
211 + CountSnow(house1_x, house1_y, 17, 10) - SPACES)*100)/138;
212 ! (You get points for destroying your own house, too)
214 CopyArray(score_array, player1_score);
215 AddShort(player1_score, score_array, destroyed*destroyed);
217 CopyArray(score_array, player2_score);
218 AddShort(player2_score, score_array, destroyed*destroyed);
230 'S', 'H', 'T', 'Q', 'R', 'L', 'C', 'O':
231 ClearUserInterface();
241 @set_cursor 8 dialog_x;
243 @set_cursor 9 dialog_x;
245 @set_cursor screen_height 1;
251 ! Get the position of x y in snow_world array
253 if (x < 1 || x > screen_width || y < 5 || y > screen_height)
256 return (y - 5)*screen_width + x;
259 [ CountDestroyed ch x y wid hgt i j n count;
260 for (i = x: i < x + wid: i++) {
261 for (j = y: j < y + hgt: j++) {
263 if (snow_world->n == ch)
270 [ CountSnow xx yy wid hgt;
271 return CountDestroyed('*', xx, yy, wid, hgt);
274 [ ChangeWorld x y num i;
275 for (i = 0: i < num: i++)
276 ChangeSnowWorld(' ', x + i, y);
279 [ ChangeSnowWorld ch xx yy x;
285 ! ----------- Initialising and game ending stuff -------------
288 screen_width = 0->33;
289 screen_height = 0->32;
290 if (screen_width < 64)
291 print "Your interpreter detected a screen width of only ",
293 if (screen_height < 24)
294 print "Your interpreter detected a screen height of only ",
296 if (screen_width < 64 || screen_height < 24) {
297 print "To play Tornado you need at least 64 x 24.^^";
300 if (screen_width > 80) screen_width = 80;
302 if ((0->1) & 128 == 0) {
303 print "Your interpreter apparently doesn't support timed events.",
304 " This game should be pretty tiresome to play without, sorry.^";
308 print "Your interpreter doesn't obey the Z-Machine standard. Z-Tornado",
309 " will probably not work correctly on such an interpreter.^";
316 dialog_x = screen_width/2 - 16;
319 if (colour) @set_colour 9 2;
321 house1_y = screen_height - 10;
322 house2_x = screen_width - 21;
323 house2_y = screen_height - 10;
324 fields = screen_height*screen_width - 5*screen_width;
334 ! There might be some bug in there, because Windows Frotz 2002 doesn't draw
335 ! the dialog window correctly after asking for the first player's name
338 for (i = 2: i < 17: i++) {
339 player1_name->i = ' ';
340 player2_name->i = ' ';
342 @set_cursor 8 dialog_x;
343 print "Please enter your name Player 1";
344 @set_cursor 9 dialog_x;
345 player1_name->0 = 15;
347 if (player1_name->1 == 0) {
348 ("Computer").print_to_array(player1_name);
351 @set_cursor 8 dialog_x;
352 print "Please enter your name Player 2";
353 @set_cursor 9 dialog_x;
355 @set_cursor 9 dialog_x;
356 player2_name->0 = 15;
358 if (player2_name->1 == 0) {
359 ("Computer").print_to_array(player2_name);
362 @set_cursor screen_height 1;
371 Nullify(player1_score);
372 Nullify(player2_score);
379 for (i = 0: i < fields: i++)
389 "/'/////////////`@@92"
397 Array temp_array -> 20;
398 [ InitHouse nr i j x y tmp;
407 for (j = 1: j <= 10: j++) {
408 tmp = GetLoc(x, y + j - 1);
409 (building-->j).print_to_array(temp_array);
410 for (i = 2: i < 19: i++)
411 snow_world->tmp++ = temp_array->i;
415 [ ContinueGame yesno;
419 while (yesno ~= 'Y' && yesno ~= 'N')
427 y = screen_height - 2;
436 print "^^[Trying to save highscore file]^";
437 @save highscore_array 220 highscore_file -> x;
439 print "^[Couldn't save the highscore file, sorry.]^";
440 print "^^Thanks for playing Tornado!^^";
443 ! ---------------- Low level routines ---------------------
445 ! Read in a character/digit from the keyboard
450 ! This should make the random function more random.
451 @read_char 1 1 SeedRand -> k;
452 for (k = 0: k < randseed: k++)
455 ! Convert lower case to upper case so we only have to test
456 ! for half of the cases
457 if ('a' <= x && x <= 'z')
458 return x - ('a' - 'A');
462 [ SeedRand; randseed++; rfalse; ];
464 ! Read in numbers from -99 to 999 (We really only need -9 to 9)
465 ! If the player doesn't type a number, or anything, we return 0.
467 [ ReadNumber x y neg tens sum;
470 if (num_array->1 == 0)
473 if (num_array->2 == '-') {
477 for (sum = 0: x < num_array->1 + 2: x++) {
478 if (num_array->x >= '0' && num_array->x <= '9') {
479 for (tens = 1, y = num_array->1: y + 1 > x: y--)
481 sum = sum + (num_array->x - '0') * tens;
489 ! Pauses for x/10 seconds
491 @read_char 1 x Interrupt -> t;
494 [ Interrupt; rtrue; ];