1 /* Tower Toppler - Nebulus
2 * Copyright (C) 2000-2012 Andreas R�ver
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "screen.h"
20
21 #include "archi.h"
22 #include "sprites.h"
23 #include "robots.h"
24 #include "stars.h"
25 #include "points.h"
26 #include "toppler.h"
27 #include "snowball.h"
28 #include "level.h"
29 #include "decl.h"
30 #include "keyb.h"
31 #include "configuration.h"
32
33 #include <string.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <wchar.h>
37
38 static SDL_Surface *display;
39
40 static int color_ramp_radj = 3;
41 static int color_ramp_gadj = 5;
42 static int color_ramp_badj = 7;
43
44 static Uint8 *slicedata, *battlementdata, *crossdata;
45
46 static int slicestart;
47 static int battlementstart;
48
49 static Uint8 robotcount;
50
51 typedef struct {
52 Uint8 count; // how many pictures are in the animation of this robot
53 unsigned short start; // number of first robot
54 } robot_data;
55
56 robot_data * robots; // array with robot data, robotcount contains size
57
58 static unsigned short ballst, boxst, snowballst, starst, crossst,
59 fishst, subst, torb;
60 static int topplerstart;
61
62 static unsigned short step, elevatorsprite, stick;
63
64 /* table used to calculate the distance of an object from the center of the
65 tower that is at x degrees on the tower */
66 static int sintab[TOWER_ANGLES];
67
68 /* this table is used for the waves of the water */
69 static Sint8 waves[0x80];
70
71 /* this value added to the start of the animal sprites leads to
72 the mirrored ones */
73 #define mirror 37
74
75 /* the state of the flashing boxes */
76 static int boxstate;
77
78 static struct {
79 int xstart; // x start position
80 int width; // width of door
81 unsigned short s[3]; // the sprite index for the 3 layers of the door
82 Uint8 *data[3]; // the data for the 3 layers of the door (pixel info for recoloring)
83 } doors[73];
84
85 #define MAXCHARNUM 256*256
86
87 static struct {
88 unsigned short s;
89 unsigned char width;
90 } fontchars[MAXCHARNUM];
91
92 /* bonus game scrolling layer */
93 typedef struct {
94 long xpos, ypos; // position of the layer
95 long xrepeat; // how often the image repeats
96 long width, height; // size of the layer
97 int num, den; // speed
98 Uint16 image;
99 } _scroll_layer;
100
101 /* # of scrolling layers in the bonus game */
102 static int num_scrolllayers;
103 /* tower layering depth and scrolling speed in the bonus game */
104 static int sl_tower_depth,
105 sl_tower_num,
106 sl_tower_den;
107 static _scroll_layer *scroll_layers;
108
109 Uint8 towerpal[2*256];
110 Uint8 crosspal[2*256];
111
112 Uint8 last_towercol_r, last_towercol_g, last_towercol_b;
113
color_ramp1(int * c,int * adj,int min,int max)114 void color_ramp1(int *c, int *adj, int min, int max) {
115 *c = *c + *adj;
116 if (*c > max - abs(*adj)) {
117 *c = max;
118 *adj = -(*adj);
119 } else if (*c < min + abs(*adj)) {
120 *c = min;
121 *adj = -(*adj);
122 }
123 }
124
scr_color_ramp(int * r,int * g,int * b)125 void scr_color_ramp(int *r, int *g, int *b) {
126 color_ramp1(r, &color_ramp_radj, 1, 255);
127 color_ramp1(g, &color_ramp_gadj, 1, 255);
128 color_ramp1(b, &color_ramp_badj, 1, 255);
129 }
130
131 void
scr_savedisplaybmp(char * fname)132 scr_savedisplaybmp(char *fname)
133 {
134 SDL_SaveBMP(display, fname);
135 }
136
137 /*
138 * Set the pixel at (x, y) to the given value
139 * NOTE: The surface must be locked before calling this!
140 */
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)141 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
142 {
143 int bpp = surface->format->BytesPerPixel;
144 /* Here p is the address to the pixel we want to set */
145 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
146
147 switch(bpp) {
148 case 1:
149 *p = pixel;
150 break;
151
152 case 2:
153 *(Uint16 *)p = pixel;
154 break;
155
156 case 3:
157 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
158 p[0] = (pixel >> 16) & 0xff;
159 p[1] = (pixel >> 8) & 0xff;
160 p[2] = pixel & 0xff;
161 } else {
162 p[0] = pixel & 0xff;
163 p[1] = (pixel >> 8) & 0xff;
164 p[2] = (pixel >> 16) & 0xff;
165 }
166 break;
167
168 case 4:
169 *(Uint32 *)p = pixel;
170 break;
171 }
172 }
173
174
175
scr_loadsprites(spritecontainer * spr,file * fi,int num,int w,int h,bool sprite,const Uint8 * pal,bool use_alpha)176 Uint16 scr_loadsprites(spritecontainer *spr, file * fi, int num, int w, int h, bool sprite, const Uint8 *pal, bool use_alpha) {
177 Uint16 erg = 0;
178 Uint8 b, a;
179 SDL_Surface *z;
180 Uint32 pixel;
181
182 for (int t = 0; t < num; t++) {
183 z = SDL_CreateRGBSurface(SDL_SWSURFACE | (sprite) ? SDL_SRCALPHA : 0,
184 w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, (sprite & use_alpha) ? 0xFF000000 : 0);
185
186 if (sprite & !use_alpha)
187 SDL_SetColorKey(z, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(z->format, 1, 1, 1));
188
189 for (int y = 0; y < h; y++)
190 for (int x = 0; x < w; x++) {
191 b = fi->getbyte();
192 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]);
193 if (sprite) {
194 a = fi->getbyte();
195 if (use_alpha) {
196 pixel=SDL_MapRGBA(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2],a);
197 } else {
198 if (a<128)
199 pixel=SDL_MapRGB(z->format,1,1,1);
200 else
201 {
202 if (((pal[b*3+2] == 1) && (pal[b*3+1] == 1)) || (pal[b*3] == 1))
203 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]+1);
204 else
205 /* ok, this is the case where we have a sprite and don't want
206 to use alpha blending, so we use normal sprites with key color
207 instead, this is much faster. So if the pixel is more than 50% transparent
208 make the whole pixel transparent by setting this pixel to the
209 key color. if the pixel is not supoosed to be transparent
210 we need to check if the pixel color is by accident the key color,
211 if so we alter is slightly */
212 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]);
213 }
214 }
215 }
216 putpixel(z,x,y,pixel);
217 }
218
219 SDL_Surface * z2 = SDL_DisplayFormatAlpha(z);
220 SDL_FreeSurface(z);
221 z = z2;
222
223 if (t == 0)
224 erg = spr->save(z);
225 else
226 spr->save(z);
227 }
228
229 return erg;
230 }
231
232
scr_gensprites(spritecontainer * spr,int num,int w,int h,bool sprite,bool use_alpha,bool screenformat)233 static Uint16 scr_gensprites(spritecontainer *spr, int num, int w, int h, bool sprite, bool use_alpha, bool screenformat) {
234 Uint16 erg = 0;
235 SDL_Surface *z;
236
237 for (int t = 0; t < num; t++) {
238 z = SDL_CreateRGBSurface(SDL_SWSURFACE | (sprite && use_alpha) ? SDL_SRCALPHA : 0,
239 w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, (sprite && use_alpha) ? 0xFF000000 : 0);
240
241 if (sprite & !use_alpha)
242 /* SDL_RLEACCEL is not allowed here, because we need to edit the data later
243 on for the new colors */
244 SDL_SetColorKey(z, SDL_SRCCOLORKEY, SDL_MapRGB(z->format, 1, 1, 1));
245
246 if (screenformat) {
247 SDL_Surface * z2 = SDL_DisplayFormat(z);
248 SDL_FreeSurface(z);
249 z = z2;
250 }
251
252 if (t == 0)
253 erg = spr->save(z);
254 else
255 spr->save(z);
256 }
257
258 return erg;
259 }
260
scr_regensprites(Uint8 * data,SDL_Surface * const target,int num,int w,int h,bool sprite,const Uint8 * pal,bool use_alpha,bool screenformat)261 static void scr_regensprites(Uint8 *data, SDL_Surface * const target, int num, int w, int h, bool sprite, const Uint8 *pal, bool use_alpha, bool screenformat) {
262 Uint8 a, b;
263 Uint32 datapos = 0;
264 SDL_Surface * z;
265 Uint32 pixel;
266
267 if (screenformat) {
268 z = SDL_CreateRGBSurface(SDL_SWSURFACE | (sprite && use_alpha) ? SDL_SRCALPHA : 0,
269 w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, (sprite && use_alpha) ? 0xFF000000 : 0);
270
271 if (sprite & !use_alpha)
272 /* SDL_RLEACCEL is not allowed here, because we need to edit the data later
273 on for the new colors */
274 SDL_SetColorKey(z, SDL_SRCCOLORKEY, SDL_MapRGB(z->format, 1, 1, 1));
275 } else
276 z = target;
277
278 for (int t = 0; t < num; t++)
279 for (int y = 0; y < h; y++)
280 for (int x = 0; x < w; x++) {
281 b = data[datapos++];
282 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]);
283 if (sprite) {
284 a = data[datapos++];
285 if (use_alpha) {
286 pixel=SDL_MapRGBA(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2],a);
287 } else {
288 if (a<128)
289 pixel=SDL_MapRGB(z->format,1,1,1);
290 else
291 {
292 if (((pal[b*3+2] == 1) && (pal[b*3+1] == 1)) || (pal[b*3] == 1))
293 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]+1);
294 else
295 /* ok, this is the case where we have a sprite and don't want
296 to use alpha blending, so we use normal sprites with key color
297 instead, this is much faster. So if the pixel is more than 50% transparent
298 make the whole pixel transparent by setting this pixel to the
299 key color. if the pixel is not supoosed to be transparent
300 we need to check if the pixel color is by accident the key color,
301 if so we alter is slightly */
302 pixel=SDL_MapRGB(z->format,pal[b*3 + 0],pal[b*3 + 1],pal[b*3 + 2]);
303 }
304 }
305 }
306 putpixel(z,x,y,pixel);
307 }
308 if (screenformat) {
309 SDL_Rect r;
310 r.h = h;
311 r.w = w;
312 r.x = 0;
313 r.y = 0;
314 SDL_BlitSurface(z, &r, target, &r);
315
316 SDL_FreeSurface(z);
317 }
318 }
319
scr_read_palette(file * fi,Uint8 * pal)320 void scr_read_palette(file * fi, Uint8 *pal) {
321 Uint8 b;
322 b = fi->getbyte();
323
324 fi->read(pal, (Uint32)b*3+3);
325 }
326
327
328 /* loads all the graphics */
loadgraphics(Uint8 what)329 static void loadgraphics(Uint8 what) {
330
331 unsigned char pal[3*256];
332 int t;
333
334 if (what == 0xff) {
335
336 file fi(dataarchive, grafdat);
337
338 fi.read(towerpal, 2*256);
339
340 slicedata = (Uint8*)malloc(SPR_SLICESPRITES * SPR_SLICEWID * SPR_SLICEHEI);
341 fi.read(slicedata, SPR_SLICESPRITES * SPR_SLICEWID * SPR_SLICEHEI);
342
343 battlementdata = (Uint8*)malloc(SPR_BATTLFRAMES * SPR_BATTLWID * SPR_BATTLHEI);
344 fi.read(battlementdata, SPR_BATTLFRAMES * SPR_BATTLWID * SPR_BATTLHEI);
345
346 slicestart = scr_gensprites(&restsprites, SPR_SLICESPRITES, SPR_SLICEWID, SPR_SLICEHEI, false, false, true);
347 battlementstart = scr_gensprites(&restsprites, SPR_BATTLFRAMES, SPR_BATTLWID, SPR_BATTLHEI, false, false, true);
348
349 for (t = -36; t < 37; t++) {
350
351 doors[t+36].xstart = fi.getword();
352 doors[t+36].width = fi.getword();
353
354 for (int et = 0; et < 3; et++)
355 if (doors[t+36].width != 0) {
356 doors[t+36].s[et] = scr_gensprites(&restsprites, 1, doors[t+36].width, 16, false, false, true);
357 doors[t+36].data[et] = (Uint8*)malloc(doors[t+36].width*16);
358 fi.read(doors[t+36].data[et], doors[t+36].width*16);
359 } else {
360 doors[t+36].s[et] = 0;
361 doors[t+36].data[et] = NULL;
362 }
363 }
364
365 for (t = 0; t < 256; t++) {
366 unsigned char c1, c2;
367
368 c1 = fi.getbyte();
369 c2 = fi.getbyte();
370
371 pal[3*t] = c1;
372 pal[3*t+1] = c2;
373 pal[3*t+2] = c2;
374 }
375
376 step = scr_loadsprites(&restsprites, &fi, SPR_STEPFRAMES, SPR_STEPWID, SPR_STEPHEI, false, pal, false);
377 elevatorsprite = scr_loadsprites(&restsprites, &fi, SPR_ELEVAFRAMES, SPR_ELEVAWID, SPR_ELEVAHEI, false, pal, false);
378 stick = scr_loadsprites(&restsprites, &fi, 1, SPR_STICKWID, SPR_STICKHEI, false, pal, false);
379 }
380
381 {
382 file fi(dataarchive, topplerdat);
383
384 scr_read_palette(&fi, pal);
385
386 topplerstart = scr_loadsprites(&objectsprites, &fi, 74, SPR_HEROWID, SPR_HEROHEI, true, pal, config.use_alpha_sprites());
387 }
388
389 {
390 file fi(dataarchive, spritedat);
391
392 scr_read_palette(&fi, pal);
393
394 robotcount = fi.getbyte();
395
396 robots = new robot_data[robotcount];
397
398 for (t = 0; t < 8; t++) {
399 robots[t].count = fi.getbyte();
400 robots[t].start = scr_loadsprites(&objectsprites, &fi, robots[t].count, SPR_ROBOTWID, SPR_ROBOTHEI, true, pal, config.use_alpha_sprites());
401 }
402
403 scr_read_palette(&fi, pal);
404 ballst = scr_loadsprites(&objectsprites, &fi, 2, SPR_ROBOTWID, SPR_ROBOTHEI, true, pal, config.use_alpha_sprites());
405
406 scr_read_palette(&fi, pal);
407 boxst = scr_loadsprites(&objectsprites, &fi, 16, SPR_BOXWID, SPR_BOXHEI, true, pal, config.use_alpha_sprites());
408
409 scr_read_palette(&fi, pal);
410 snowballst = scr_loadsprites(&objectsprites, &fi, 1, SPR_AMMOWID, SPR_AMMOHEI, true, pal, config.use_alpha_sprites());
411
412 scr_read_palette(&fi, pal);
413 starst = scr_loadsprites(&objectsprites, &fi, 16, SPR_STARWID, SPR_STARHEI, true, pal, config.use_alpha_sprites());
414 sts_init(starst + 9, NUM_STARS);
415
416 scr_read_palette(&fi, pal);
417 fishst = scr_loadsprites(&objectsprites, &fi, 32*2, SPR_FISHWID, SPR_FISHHEI, true, pal, config.use_alpha_sprites());
418
419 scr_read_palette(&fi, pal);
420 subst = scr_loadsprites(&objectsprites, &fi, 31, SPR_SUBMWID, SPR_SUBMHEI, true, pal, config.use_alpha_sprites());
421
422 scr_read_palette(&fi, pal);
423 torb = scr_loadsprites(&objectsprites, &fi, 1, SPR_TORPWID, SPR_TORPHEI, true, pal, config.use_alpha_sprites());
424 }
425
426 {
427 file fi(dataarchive, crossdat);
428
429 Uint8 numcol = fi.getbyte();
430
431 for (t = 0; t < numcol + 1; t++) {
432 crosspal[2*t] = fi.getbyte();
433 fi.getbyte();
434 crosspal[2*t+1] = fi.getbyte();
435 }
436
437 crossdata = (Uint8*)malloc(120*SPR_CROSSWID*SPR_CROSSHEI*2);
438 fi.read(crossdata, 120*SPR_CROSSWID*SPR_CROSSHEI*2);
439
440 crossst = scr_gensprites(&objectsprites, 120, SPR_CROSSWID, SPR_CROSSHEI, true, config.use_alpha_sprites(), false);
441 }
442 }
443
scr_numrobots(void)444 Uint8 scr_numrobots(void) { return robotcount; }
445
446
scr_settowercolor(Uint8 r,Uint8 g,Uint8 b)447 void scr_settowercolor(Uint8 r, Uint8 g, Uint8 b) {
448
449 Uint8 pal[3*256];
450
451 int t;
452 int bw, gw, rw;
453
454 for (t = 0; t < 256; t++) {
455 rw = (int)r*towerpal[2*t+1] + (255-(int)r)*towerpal[2*t];
456 gw = (int)g*towerpal[2*t+1] + (255-(int)g)*towerpal[2*t];
457 bw = (int)b*towerpal[2*t+1] + (255-(int)b)*towerpal[2*t];
458
459 rw /= 256;
460 gw /= 256;
461 bw /= 256;
462
463 pal[3*t] = rw;
464 pal[3*t+1] = gw;
465 pal[3*t+2] = bw;
466 }
467
468 for (t = 0; t < SPR_SLICESPRITES; t++)
469 scr_regensprites(slicedata + t*SPR_SLICEWID*SPR_SLICEHEI, restsprites.data(slicestart + t), 1, SPR_SLICEWID, SPR_SLICEHEI, false, pal, false, true);
470
471 for (t = 0; t < SPR_BATTLFRAMES; t++)
472 scr_regensprites(battlementdata + t*SPR_BATTLWID*SPR_BATTLHEI, restsprites.data(battlementstart + t), 1, SPR_BATTLWID, SPR_BATTLHEI, false, pal, false, true);
473
474 for (t = -36; t < 37; t++)
475 for (int et = 0; et < 3; et++)
476 if (doors[t+36].width != 0)
477 scr_regensprites(doors[t+36].data[et], restsprites.data(doors[t+36].s[et]), 1, doors[t+36].width, SPR_SLICEHEI, false, pal, false, true);
478
479 last_towercol_r = r;
480 last_towercol_g = g;
481 last_towercol_b = b;
482 }
483
resettowercolor(void)484 void resettowercolor(void) {
485 scr_settowercolor(last_towercol_r, last_towercol_g, last_towercol_b);
486 }
487
scr_setcrosscolor(Uint8 rk,Uint8 gk,Uint8 bk)488 void scr_setcrosscolor(Uint8 rk, Uint8 gk, Uint8 bk) {
489
490 Uint8 pal[256*3];
491
492 int t, r, g, b;
493
494 for (t = 0; t < 256; t++) {
495 r = g = b = crosspal[2*t];
496
497 r += ((int)crosspal[2*t+1] * rk) / 256;
498 g += ((int)crosspal[2*t+1] * gk) / 256;
499 b += ((int)crosspal[2*t+1] * bk) / 256;
500
501 if (r > 255)
502 r = 255;
503 if (g > 255)
504 g = 255;
505 if (b > 255)
506 b = 255;
507
508 pal[3*t+0] = r;
509 pal[3*t+1] = g;
510 pal[3*t+2] = b;
511 }
512
513 for (t = 0; t < 120; t++) {
514 scr_regensprites(crossdata + t*SPR_CROSSWID*SPR_CROSSHEI*2,
515 objectsprites.data(crossst+t),
516 1, SPR_CROSSWID, SPR_CROSSHEI, true, pal, config.use_alpha_sprites(), false);
517 }
518 }
519
loadfont(void)520 static void loadfont(void) {
521
522 unsigned char pal[256*3];
523 Uint16 c;
524 int fontheight;
525
526 file fi(dataarchive, fontdat);
527
528 scr_read_palette(&fi, pal);
529
530 fontheight = fi.getbyte();
531
532 while (!fi.eof()) {
533 c = fi.getword();
534
535 if (!c) break;
536
537 fontchars[c].width = fi.getbyte();
538 fontchars[c].s = scr_loadsprites(&fontsprites, &fi, 1, fontchars[c].width, fontheight, true, pal, config.use_alpha_font());
539 }
540 }
541
loadscroller(void)542 static void loadscroller(void) {
543
544 file fi(dataarchive, scrollerdat);
545
546 Uint8 layers;
547 Uint8 towerpos;
548 Uint8 pal[3*256];
549
550 layers = fi.getbyte();
551
552 num_scrolllayers = layers;
553
554 assert_msg(num_scrolllayers > 1, "Must have at least 2 scroll layers!");
555
556 scroll_layers = new _scroll_layer[layers];
557 assert_msg(scroll_layers, "Failed to alloc memory for bonus scroller!");
558
559 towerpos = fi.getbyte();
560
561 sl_tower_depth = towerpos;
562
563 sl_tower_num = fi.getword();
564 sl_tower_den = fi.getword();
565
566 for (int l = 0; l < layers; l++) {
567
568 scroll_layers[l].xpos = fi.getword();
569 scroll_layers[l].ypos = fi.getword();
570 scroll_layers[l].width = fi.getword();
571 scroll_layers[l].height = fi.getword();
572 scroll_layers[l].num = fi.getword();
573 scroll_layers[l].den = fi.getword();
574 scroll_layers[l].xrepeat = fi.getword();
575
576 scr_read_palette(&fi, pal);
577
578 scroll_layers[l].image = scr_loadsprites(&layersprites, &fi, 1,
579 scroll_layers[l].width, scroll_layers[l].height,
580 l != 0, pal, config.use_alpha_layers());
581 }
582 }
583
load_sprites(Uint8 what)584 static void load_sprites(Uint8 what) {
585 if ((what == 0xff) || (what & RL_OBJECTS))
586 loadgraphics(what);
587
588 if (what & RL_FONT)
589 loadfont();
590
591 if (what & RL_SCROLLER)
592 loadscroller();
593 }
594
free_memory(Uint8 what)595 static void free_memory(Uint8 what) {
596 int t;
597
598 if (what == 0xff) {
599 free(slicedata);
600 free(battlementdata);
601 }
602
603 if (what & RL_OBJECTS) {
604 free(crossdata);
605 delete [] robots;
606 }
607
608 if (what & RL_SCROLLER)
609 delete [] scroll_layers;
610
611 if (what == 0xff)
612 for (t = -36; t < 37; t++)
613 for (int et = 0; et < 3; et++)
614 if (doors[t+36].data[et])
615 free(doors[t+36].data[et]);
616 }
617
scr_reload_sprites(Uint8 what)618 void scr_reload_sprites(Uint8 what) {
619 free_memory(what);
620 load_sprites(what);
621 resettowercolor();
622 }
623
scr_init(void)624 void scr_init(void) {
625
626 scr_reinit();
627
628 load_sprites(0xff);
629
630 /* initialize sinus table */
631 for (int i = 0; i < TOWER_ANGLES; i++)
632 sintab[i] = int(sin(i * 2 * M_PI / TOWER_ANGLES) * (TOWER_RADIUS + SPR_STEPWID / 2) + 0.5);
633
634
635 /* initialize wave table */
636 for (int t = 0; t < 0x80; t++)
637 waves[t] = (Sint8)(8 * (sin(t * 2.0 * M_PI / 0x7f)) +
638 4 * (sin(t * 3.0 * M_PI / 0x7f+2)) +
639 3 * (sin(t * 5.0 * M_PI / 0x7f+3)) + 0.5);
640
641 }
642
scr_reinit()643 void scr_reinit() {
644 display = SDL_SetVideoMode(SCREENWID, SCREENHEI, 16, (config.fullscreen()) ? (SDL_FULLSCREEN) : (0));
645 assert_msg(display, "could not open display");
646 }
647
scr_done(void)648 void scr_done(void) {
649 free_memory(0xff);
650 sts_done();
651 }
652
cleardesk(long height)653 static void cleardesk(long height) {
654 SDL_Rect r;
655 height *= 4;
656
657 /* clear left side from top to water */
658 r.w = (SCREENWID - SPR_SLICEWID) / 2;
659 if (height < (SCREENHEI / 2))
660 r.h = (SCREENHEI / 2) + height;
661 else
662 r.h = SCREENHEI;
663 r.x = r.y = 0;
664 SDL_FillRect(display, &r, 0);
665
666 /* clear right side from top to water */
667 r.x = (SCREENWID - SPR_SLICEWID) / 2 + SPR_SLICEWID;
668 SDL_FillRect(display, &r, 0);
669
670 /* clear middle row from top to battlement */
671 int upend = (SCREENHEI / 2) - (lev_towerrows() * SPR_SLICEHEI - height + SPR_BATTLHEI);
672 if (upend > 0) {
673 r.x = (SCREENWID - SPR_SLICEWID) / 2;
674 r.w = SPR_SLICEWID;
675 r.h = upend;
676 SDL_FillRect(display, &r, 0);
677 }
678 }
679
scr_darkenscreen(void)680 void scr_darkenscreen(void) {
681
682 if (!config.use_alpha_darkening())
683 return;
684
685 scr_putbar(0, 0, SCREENWID, SCREENHEI, 0, 0, 0, 128);
686 }
687
688
689 /*
690 angle: 0 means column 0 is in front
691 8 means column 1 ...
692
693 height: 0 means row 0 is in the middle
694 4 means row 1 ...
695 */
puttower(long angle,long height,long towerheight,int shift=0)696 static void puttower(long angle, long height, long towerheight, int shift = 0) {
697
698 /* calculate the blit position of the lowest slice considering the current
699 * vertical position
700 */
701 int slice = 0;
702 int ypos = SCREENHEI / 2 - SPR_SLICEHEI + height;
703
704 /* now go up until we go over the top of the screen or reach the
705 * top of the tower
706 */
707 while ((ypos > -SPR_SLICEHEI) && (slice < towerheight)) {
708
709 /* if we are over the bottom of the screen, draw the slice */
710 if (ypos < SCREENHEI)
711 scr_blit(restsprites.data(slicestart + (angle % SPR_SLICEANGLES)), (SCREENWID / 2) - (SPR_SLICEWID / 2) + shift, ypos);
712
713 slice++;
714 angle = (angle + (SPR_SLICEANGLES / 2)) % TOWER_ANGLES;
715 ypos -= SPR_SLICEHEI;
716 }
717 }
718
putbattlement(long angle,long height)719 static void putbattlement(long angle, long height) {
720
721 /* calculate the lower border position of the battlement */
722 int upend = (SCREENHEI / 2) - (lev_towerrows() * SPR_SLICEHEI - height);
723
724 /* if it's below the top of the screen, then blit the battlement */
725 if (upend > 0)
726 scr_blit(restsprites.data((angle % SPR_BATTLFRAMES) + battlementstart),
727 (SCREENWID / 2) - (SPR_BATTLWID / 2), upend - SPR_BATTLHEI);
728 }
729
putwater(long height)730 static void putwater(long height) {
731
732 static const char simple_waves[] = {
733 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
734 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
735 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
736 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
737 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
738 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
739 3, 3 };
740
741 static int wavetime = 0;
742
743 height *= 4;
744
745 if (height < (SCREENHEI / 2)) {
746
747 switch(config.waves_type()) {
748
749 case configuration::waves_expensive:
750 {
751 int source_line = (SCREENHEI / 2) + height - 1;
752
753 Uint8 buffer[4] = {0,0,0,0};
754
755 for (int y = 0; y < (SCREENHEI / 2) - height; y++) {
756
757 Uint8 * target = (Uint8*)display->pixels + ((SCREENHEI/2) + height + y) * display->pitch;
758
759 for (int x = 0; x < SCREENWID; x++) {
760 Sint16 dx = waves[(x+y+12*wavetime) & 0x7f] + waves[(2*x-y+11*wavetime) & 0x7f];
761 Sint16 dy = waves[(x-y+13*wavetime) & 0x7f] + waves[(2*x-3*y-14*wavetime) & 0x7f];
762
763 dx = dx * y / (SCREENHEI/2);
764 dy = dy * y / (SCREENHEI/2);
765
766 if ((x+dx < 0) || (x+dx > SCREENWID) || (source_line+dy < 0))
767 memcpy(target, &buffer, display->format->BytesPerPixel);
768 else
769 memcpy(target, (Uint8*)display->pixels +
770 (x+dx) * display->format->BytesPerPixel +
771 (source_line+dy) * display->pitch, display->format->BytesPerPixel);
772
773 target += display->format->BytesPerPixel;
774 }
775 scr_putbar(0, (SCREENHEI/2) + height + y, SCREENWID, 1, 0, 0, y, 128);
776 source_line --;
777 }
778 }
779 break;
780 case configuration::waves_simple:
781 {
782 int horizontal_shift;
783
784 scr_putbar(0, (SCREENHEI / 2) + height, 10, (SCREENHEI / 2) - height, 0, 0, 0, 255);
785 scr_putbar(SCREENWID-10, (SCREENHEI / 2) + height, 10, (SCREENHEI / 2) - height, 0, 0, 0, 255);
786
787 for (int y = 0; y < (SCREENHEI / 2) - height; y++) {
788
789 int target_line = (SCREENHEI / 2) + height + y;
790 int source_line = (SCREENHEI / 2) + height - y - 1 - simple_waves[(wavetime * 4 + y * 2) & 0x7f];
791 if (source_line < 0)
792 source_line = 0;
793
794 int z = simple_waves[(wavetime*5 + y) & 0x7f];
795 if (abs(z - 4) > y) {
796 if (z < 4)
797 horizontal_shift = 4 - y;
798 else
799 horizontal_shift = 4 + y;
800 } else {
801 horizontal_shift = z;
802 }
803
804 SDL_Rect r1;
805 SDL_Rect r2;
806
807 r1.w = r2.w = SCREENWID;
808 r1.h = r2.h = 1;
809
810 r2.y = target_line;
811 r1.y = source_line;
812
813 if (horizontal_shift > 0) {
814 r1.x = horizontal_shift;
815 r2.x = 0;
816 } else {
817 r1.x = 0;
818 r2.x = -horizontal_shift;
819 }
820
821 SDL_BlitSurface(display, &r1, display, &r2);
822 scr_putbar(0, target_line, SCREENWID, 1, 0, 0, y, 128);
823
824 }
825 }
826 break;
827 case configuration::waves_nonreflecting:
828 for (int y = 0; y < (SCREENHEI / 2) - height; y++)
829 scr_putbar(0, SCREENHEI/2 + height + y, SCREENWID, 1, 0, 0, 30 + y/2, 255);
830 break;
831 }
832 }
833
834 wavetime++;
835 }
836
scr_textlength(const char * s,int chars)837 int scr_textlength(const char *s, int chars) {
838 int len = 0;
839 int pos = 0;
840 mbstate_t state;
841 memset (&state, '\0', sizeof (state));
842 wchar_t tmp;
843
844 while (s[pos] && (chars > 0)) {
845
846 size_t nbytes = mbrtowc (&tmp, &s[pos], chars, &state);
847 if (nbytes <= 0)
848 return 0;
849
850 if (tmp == ' ') {
851 len += FONTMINWID;
852 } else {
853 if (fontchars[tmp & 0xffff].width != 0)
854 len += fontchars[tmp & 0xffff].width + 3;
855 }
856
857 pos += nbytes;
858 chars -= nbytes;
859 }
860
861 return len;
862 }
863
scr_writetext_center(long y,const char * s)864 void scr_writetext_center(long y, const char *s) {
865 scr_writetext ((SCREENWID - scr_textlength(s)) / 2, y, s);
866 }
867
scr_writetext_broken_center(long y,const char * s)868 void scr_writetext_broken_center(long y, const char *s) {
869
870 // ok, we try to break the text into several lines, if the lines are longer then the
871 // screenwidth
872
873 int len = strlen(s);
874 int start = 0;
875 int end = len;
876
877 while (start < len) {
878
879 while (scr_textlength(s+start, end-start+1) > SCREENWID) {
880 end--;
881 while ((end > start) && (s[end] != ' ')) end--;
882
883 if (end == start) {
884 while ((end < len) && (s[end] != ' ')) end++;
885 break;
886 }
887 }
888
889 if (s[end] == ' ') end--;
890
891 scr_writetext((SCREENWID - scr_textlength(s+start, end-start+1)) / 2, y, s+start, end-start+1);
892
893 start = end+1;
894 end = len;
895 while ((start < len) && (s[start] == ' ')) start++;
896
897 y += 40;
898
899 }
900 }
901
scr_putbar(int x,int y,int br,int h,Uint8 colr,Uint8 colg,Uint8 colb,Uint8 alpha)902 void scr_putbar(int x, int y, int br, int h, Uint8 colr, Uint8 colg, Uint8 colb, Uint8 alpha) {
903
904 if (alpha != 255) {
905
906 SDL_Surface *s = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, br, h, 16,
907 display->format->Rmask, display->format->Gmask,
908 display->format->Bmask, 0);
909 SDL_SetAlpha(s, SDL_SRCALPHA, alpha);
910
911 SDL_Rect r;
912 r.w = br;
913 r.h = h;
914 r.x = 0;
915 r.y = 0;
916
917 SDL_FillRect(s, &r, SDL_MapRGB(display->format, colr, colg, colb));
918
919 scr_blit(s, x, y);
920
921 SDL_FreeSurface(s);
922
923 } else {
924
925 SDL_Rect r;
926 r.w = br;
927 r.h = h;
928 r.x = x;
929 r.y = y;
930 SDL_FillRect(display, &r, SDL_MapRGBA(display->format, colr, colg, colb, alpha));
931 }
932 }
933
934 void
scr_putrect(int x,int y,int br,int h,Uint8 colr,Uint8 colg,Uint8 colb,Uint8 alpha)935 scr_putrect(int x, int y, int br, int h, Uint8 colr, Uint8 colg, Uint8 colb, Uint8 alpha)
936 {
937 scr_putbar(x, y, 1 , h, colr, colg, colb, alpha);
938 scr_putbar(x, y, br , 1, colr, colg, colb, alpha);
939 scr_putbar(x + br, y, 1 , h, colr, colg, colb, alpha);
940 scr_putbar(x, y + h , br + 1, 1, colr, colg, colb, alpha);
941 }
942
943 /* exchange active and inactive page */
scr_swap(void)944 void scr_swap(void) {
945 if (!tt_has_focus) {
946 scr_darkenscreen();
947 SDL_UpdateRect(display, 0, 0, 0, 0);
948 wait_for_focus();
949 }
950 SDL_UpdateRect(display, 0, 0, 0, 0);
951 }
952
scr_setclipping(int x,int y,int w,int h)953 void scr_setclipping(int x, int y, int w, int h) {
954 if (x < 0) SDL_SetClipRect(display, NULL);
955 else {
956 SDL_Rect r;
957 r.x = x;
958 r.y = y;
959 r.w = w;
960 r.h = h;
961 SDL_SetClipRect(display, &r);
962 }
963 }
964
scr_blit(SDL_Surface * s,int x,int y)965 void scr_blit(SDL_Surface * s, int x, int y) {
966 SDL_Rect r;
967 r.w = s->w;
968 r.h = s->h;
969 r.x = x;
970 r.y = y;
971 SDL_BlitSurface(s, NULL, display, &r);
972 }
973
974
975 /* draws the tower and the doors */
draw_tower(long vert,long angle)976 static void draw_tower(long vert, long angle) {
977
978 puttower(angle, vert, lev_towerrows());
979
980 int slice = 0;
981 int ypos = SCREENHEI / 2 - SPR_SLICEHEI + vert;
982
983 while (ypos > SCREENHEI) {
984 slice++;
985 ypos -= SPR_SLICEHEI;
986 }
987
988 while ((ypos > -SPR_SLICEHEI) && (slice < lev_towerrows())) {
989
990 for (int col = 0; col < 16; col++) {
991
992 int a = (col * 8 + angle + 36) % TOWER_ANGLES;
993
994 if ((a > 72) || !doors[a].width)
995 continue;
996
997 if (lev_is_door(slice, col)) {
998 if (lev_is_door_upperend(slice, col))
999 scr_blit(restsprites.data(doors[a].s[2]), (SCREENWID / 2) + doors[a].xstart, ypos);
1000 else if (lev_is_door_upperend(slice - 1, col))
1001 scr_blit(restsprites.data(doors[a].s[1]), (SCREENWID / 2) + doors[a].xstart, ypos);
1002 else
1003 scr_blit(restsprites.data(doors[a].s[0]), (SCREENWID / 2) + doors[a].xstart, ypos);
1004 }
1005 }
1006
1007 slice++;
1008 ypos -= SPR_SLICEHEI;
1009 }
1010 }
1011
draw_tower_editor(long vert,long angle,int state)1012 static void draw_tower_editor(long vert, long angle, int state) {
1013
1014 puttower(angle, vert, lev_towerrows());
1015
1016
1017 int slice = 0;
1018 int ypos = SCREENHEI / 2 - SPR_SLICEHEI + vert;
1019
1020 while (ypos > SCREENHEI) {
1021 slice++;
1022 ypos -= SPR_SLICEHEI;
1023 }
1024
1025 while ((ypos > -SPR_SLICEHEI) && (slice < lev_towerrows())) {
1026
1027 for (int col = 0; col < 16; col++) {
1028
1029 int a = (col * 8 + angle + 36) % TOWER_ANGLES;
1030
1031 if ((a > 72) || !doors[a].width)
1032 continue;
1033
1034 if (lev_is_door(slice, col)) {
1035
1036 if (lev_is_targetdoor(slice, col) && (state & 1)) continue;
1037
1038 if (lev_is_door_upperend(slice, col))
1039 scr_blit(restsprites.data(doors[a].s[2]), (SCREENWID / 2) + doors[a].xstart, ypos);
1040 else if (lev_is_door_upperend(slice - 1, col))
1041 scr_blit(restsprites.data(doors[a].s[1]), (SCREENWID / 2) + doors[a].xstart, ypos);
1042 else
1043 scr_blit(restsprites.data(doors[a].s[0]), (SCREENWID / 2) + doors[a].xstart, ypos);
1044 }
1045 }
1046
1047 slice++;
1048 ypos -= SPR_SLICEHEI;
1049 }
1050 }
1051
1052
1053 /* draws something of the environment */
putcase(unsigned char w,long x,long h)1054 static void putcase(unsigned char w, long x, long h) {
1055 long angle = 0;
1056 switch (w) {
1057
1058 case TB_EMPTY:
1059 /* blank case */
1060 break;
1061
1062 case TB_ELEV_BOTTOM:
1063 case TB_ELEV_TOP:
1064 case TB_ELEV_MIDDLE:
1065 scr_blit(restsprites.data((angle % SPR_ELEVAFRAMES) + elevatorsprite), x - (SPR_ELEVAWID / 2), h);
1066
1067 break;
1068
1069 case TB_STEP:
1070 case TB_STEP_VANISHER:
1071 case TB_STEP_LSLIDER:
1072 case TB_STEP_RSLIDER:
1073 scr_blit(restsprites.data((angle % SPR_STEPFRAMES) + step), x - (SPR_STEPWID / 2), h);
1074
1075 break;
1076
1077 case TB_STICK:
1078 case TB_STICK_BOTTOM:
1079 case TB_STICK_MIDDLE:
1080 case TB_STICK_DOOR:
1081 case TB_STICK_DOOR_TARGET:
1082 scr_blit(restsprites.data(stick), x - (SPR_STICKWID / 2), h);
1083
1084 break;
1085
1086 case TB_BOX:
1087 scr_blit(objectsprites.data(boxst + boxstate), x - (SPR_BOXWID / 2), h);
1088
1089 break;
1090 }
1091 }
1092
putcase_editor(unsigned char w,long x,long h,int state)1093 static void putcase_editor(unsigned char w, long x, long h, int state) {
1094 long angle = 0;
1095 switch (w) {
1096
1097 case TB_EMPTY:
1098 /* blank case */
1099 break;
1100
1101 case TB_ELEV_BOTTOM:
1102 scr_blit(restsprites.data((angle % SPR_ELEVAFRAMES) + elevatorsprite), x - (SPR_ELEVAWID / 2), h - (state % 4));
1103 break;
1104 case TB_STATION_MIDDLE:
1105 scr_blit(restsprites.data((angle % SPR_ELEVAFRAMES) + elevatorsprite), x - (SPR_ELEVAWID / 2), h - SPR_SLICEHEI/2 + abs(state - 8));
1106 break;
1107 case TB_STATION_TOP:
1108 scr_blit(restsprites.data((angle % SPR_ELEVAFRAMES) + elevatorsprite), x - (SPR_ELEVAWID / 2), h + (state % 4));
1109 break;
1110 case TB_STEP:
1111 scr_blit(restsprites.data(((angle % SPR_STEPFRAMES) + step)), x - (SPR_STEPWID / 2), h);
1112 break;
1113 case TB_STEP_VANISHER:
1114 if (config.use_alpha_sprites()) {
1115 SDL_Surface *s = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, SPR_STEPWID, SPR_STEPHEI, 24, 0xff, 0xff00, 0xff0000, 0);
1116 SDL_Rect r;
1117 r.w = SPR_STEPWID;
1118 r.h = SPR_STEPHEI;
1119 r.x = 0;
1120 r.y = 0;
1121 SDL_BlitSurface(restsprites.data(((angle % SPR_STEPFRAMES) + step)), NULL, s, &r);
1122 SDL_SetAlpha(s, SDL_SRCALPHA, 96);
1123 scr_blit(s, x - (SPR_STEPWID / 2), h);
1124 SDL_FreeSurface(s);
1125 } else {
1126 if (state & 1)
1127 scr_blit(restsprites.data(((angle % SPR_STEPFRAMES) + step)), x - (SPR_STEPWID / 2), h);
1128 }
1129 break;
1130 case TB_STEP_LSLIDER:
1131 scr_blit(restsprites.data(((angle % SPR_STEPFRAMES) + step)), x - (SPR_STEPWID / 2) + state % 4, h);
1132 break;
1133
1134 case TB_STEP_RSLIDER:
1135 scr_blit(restsprites.data(((angle % SPR_STEPFRAMES) + step)), x - (SPR_STEPWID / 2) - state % 4, h);
1136 break;
1137
1138 case TB_STICK:
1139 scr_blit(restsprites.data(stick), x - (SPR_STICKWID / 2), h);
1140 break;
1141
1142 case TB_BOX:
1143 scr_blit(objectsprites.data(boxst + boxstate), x - (SPR_BOXWID / 2), h);
1144 break;
1145
1146 case TB_ROBOT1:
1147 scr_blit(objectsprites.data(ballst + 1), x - (SPR_ROBOTWID / 2), h - SPR_ROBOTHEI/2);
1148 break;
1149 case TB_ROBOT2:
1150 scr_blit(objectsprites.data(ballst), x - (SPR_ROBOTWID / 2) + state / 2, h - SPR_ROBOTHEI/2);
1151 break;
1152 case TB_ROBOT3:
1153 scr_blit(objectsprites.data(ballst), x - (SPR_ROBOTWID / 2), h - SPR_ROBOTHEI/2);
1154 break;
1155 case TB_ROBOT4:
1156 scr_blit(objectsprites.data(robots[lev_robotnr()].start + state % robots[lev_robotnr()].count),
1157 x - (SPR_ROBOTWID / 2), h - SPR_ROBOTHEI/2 + abs(state - 8));
1158 break;
1159 case TB_ROBOT5:
1160 scr_blit(objectsprites.data(robots[lev_robotnr()].start + state % robots[lev_robotnr()].count),
1161 x - (SPR_ROBOTWID / 2), h - SPR_ROBOTHEI + abs(state - 8) * 2);
1162 break;
1163 case TB_ROBOT6:
1164 scr_blit(objectsprites.data(robots[lev_robotnr()].start + state % robots[lev_robotnr()].count),
1165 x - (SPR_ROBOTWID / 2) + abs(state - 8), h - SPR_SLICEHEI/2);
1166 break;
1167 case TB_ROBOT7:
1168 scr_blit(objectsprites.data(robots[lev_robotnr()].start + state % robots[lev_robotnr()].count),
1169 x - (SPR_ROBOTWID / 2) + 2 * abs(state - 8), h - SPR_SLICEHEI/2);
1170 break;
1171 }
1172 }
1173
1174
1175 /* draws a robot */
putrobot(int t,int m,long x,long h)1176 static void putrobot(int t, int m, long x, long h)
1177 {
1178 int nr;
1179
1180 if (h > (SCREENHEI + SPR_ROBOTHEI)) return;
1181
1182 switch (t) {
1183
1184 case OBJ_KIND_JUMPBALL:
1185 nr = ballst;
1186 break;
1187
1188 case OBJ_KIND_FREEZEBALL:
1189 case OBJ_KIND_FREEZEBALL_FROZEN:
1190 case OBJ_KIND_FREEZEBALL_FALLING:
1191 nr = ballst + 1;
1192 break;
1193
1194 case OBJ_KIND_DISAPPEAR:
1195 nr = starst + m * 2;
1196 break;
1197
1198 case OBJ_KIND_APPEAR:
1199 nr = starst - m * 2 + 16;
1200 break;
1201
1202 case OBJ_KIND_ROBOT_VERT:
1203 case OBJ_KIND_ROBOT_HORIZ:
1204 nr = robots[lev_robotnr()].start + ((m / 2) % robots[lev_robotnr()].count);
1205 break;
1206
1207 default:
1208 nr = 40;
1209 break;
1210 }
1211
1212 scr_blit(objectsprites.data(nr), x + (SCREENWID / 2) - (SPR_ROBOTWID / 2), h - SPR_ROBOTHEI);
1213 }
1214
scr_writetext(long x,long y,const char * s,int maxchars)1215 void scr_writetext(long x, long y, const char *s, int maxchars) {
1216
1217 mbstate_t state;
1218 memset (&state, '\0', sizeof (state));
1219 wchar_t tmp;
1220
1221 int t = 0;
1222
1223 if (maxchars == -1)
1224 maxchars = strlen(s);
1225
1226 while (s[t] && (maxchars > 0)) {
1227
1228 size_t nbytes = mbrtowc (&tmp, &s[t], maxchars, &state);
1229
1230 if (nbytes >= (size_t) -2) {
1231 return;
1232 }
1233
1234 if (tmp == ' ') {
1235 x += FONTMINWID;
1236 t += nbytes;
1237 maxchars -= nbytes;
1238 continue;
1239 }
1240
1241 if (fontchars[tmp & 0xffff].width != 0) {
1242 scr_blit(fontsprites.data(fontchars[tmp & 0xffff].s), x, y-20);
1243 x += fontchars[tmp & 0xffff].width + 3;
1244 }
1245
1246 t += nbytes;
1247 maxchars -= nbytes;
1248 }
1249 }
1250
scr_writeformattext(long x,long y,const char * s)1251 void scr_writeformattext(long x, long y, const char *s) {
1252
1253 mbstate_t state;
1254 memset (&state, '\0', sizeof (state));
1255 wchar_t tmp;
1256
1257 int len = strlen(s);
1258
1259 int origx = x;
1260 int t = 0;
1261 Uint8 towerblock = 0;
1262 while (t < len) {
1263
1264 size_t nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1265
1266 if (nbytes >= (size_t) -2) {
1267 return;
1268 }
1269
1270 t += nbytes;
1271
1272 switch(tmp) {
1273 case ' ':
1274 x += FONTMINWID;
1275 break;
1276 case '~':
1277
1278 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1279 if (nbytes >= (size_t) -2) {
1280 return;
1281 }
1282 t += nbytes;
1283
1284 switch(tmp) {
1285 case 't':
1286
1287 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1288 if (nbytes >= (size_t) -2) {
1289 return;
1290 }
1291 t += nbytes;
1292
1293 x = (tmp - '0') * 100;
1294
1295 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1296 if (nbytes >= (size_t) -2) {
1297 return;
1298 }
1299 t += nbytes;
1300
1301 x += (tmp - '0') * 10;
1302
1303 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1304 if (nbytes >= (size_t) -2) {
1305 return;
1306 }
1307 t += nbytes;
1308
1309 x += (tmp - '0');
1310
1311 break;
1312 case 'T':
1313 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1314 if (nbytes >= (size_t) -2) {
1315 return;
1316 }
1317 t += nbytes;
1318
1319 x = origx + (tmp - '0') * 100;
1320
1321 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1322 if (nbytes >= (size_t) -2) {
1323 return;
1324 }
1325 t += nbytes;
1326
1327 x += (tmp - '0') * 10;
1328
1329 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1330 if (nbytes >= (size_t) -2) {
1331 return;
1332 }
1333 t += nbytes;
1334
1335 x += (tmp - '0');
1336
1337 break;
1338 case 'b':
1339
1340 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1341 if (nbytes >= (size_t) -2) {
1342 return;
1343 }
1344 t += nbytes;
1345
1346 towerblock = conv_char2towercode(tmp);
1347 putcase(towerblock, x+16, y);
1348 x += 32;
1349 break;
1350 case 'e':
1351 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1352 if (nbytes >= (size_t) -2) {
1353 return;
1354 }
1355 t += nbytes;
1356
1357 towerblock = conv_char2towercode(tmp);
1358 putcase_editor(towerblock, x+16, y, boxstate);
1359 x += 32;
1360 break;
1361 default:
1362 assert_msg(0, "Wrong command in formatted text.");
1363 }
1364 break;
1365 default:
1366 if (fontchars[tmp & 0xffff].width != 0) {
1367 scr_blit(fontsprites.data(fontchars[tmp & 0xffff].s), x, y-20);
1368 x += fontchars[tmp & 0xffff].width + 3;
1369 }
1370 }
1371 }
1372 }
1373
scr_formattextlength(long x,long y,const char * s)1374 long scr_formattextlength(long x, long y, const char *s) {
1375 mbstate_t state;
1376 memset (&state, '\0', sizeof (state));
1377 wchar_t tmp;
1378
1379 int len = strlen(s);
1380
1381 int origx = x;
1382 int t = 0;
1383 while (t < len) {
1384
1385 size_t nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1386 if (nbytes >= (size_t) -2) return 0;
1387 t += nbytes;
1388
1389 switch(tmp) {
1390 case ' ':
1391 x += FONTMINWID;
1392 break;
1393 case '~':
1394
1395 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1396 if (nbytes >= (size_t) -2) return 0;
1397 t += nbytes;
1398
1399 switch(tmp) {
1400 case 't':
1401
1402 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1403 if (nbytes >= (size_t) -2) return 0;
1404 t += nbytes;
1405 x = (tmp - '0') * 100;
1406
1407 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1408 if (nbytes >= (size_t) -2) return 0;
1409 t += nbytes;
1410 x += (tmp - '0') * 10;
1411
1412 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1413 if (nbytes >= (size_t) -2) return 0;
1414 t += nbytes;
1415 x += (tmp - '0');
1416
1417 break;
1418 case 'T':
1419 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1420 if (nbytes >= (size_t) -2) return 0;
1421 t += nbytes;
1422 x = origx + (tmp - '0') * 100;
1423
1424 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1425 if (nbytes >= (size_t) -2) return 0;
1426 t += nbytes;
1427 x += (tmp - '0') * 10;
1428
1429 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1430 if (nbytes >= (size_t) -2) return 0;
1431 t += nbytes;
1432 x += (tmp - '0');
1433
1434 break;
1435 case 'b':
1436 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1437 if (nbytes >= (size_t) -2) return 0;
1438 t += nbytes;
1439 x += 32;
1440 break;
1441 case 'e':
1442 nbytes = mbrtowc (&tmp, &s[t], len-t, &state);
1443 if (nbytes >= (size_t) -2) return 0;
1444 t += nbytes;
1445 x += 32;
1446 break;
1447 default:
1448 assert_msg(0, "Wrong command in formatted text.");
1449 }
1450 break;
1451 default:
1452 if (fontchars[tmp & 0xffff].width != 0) {
1453 x += fontchars[tmp & 0xffff].width + 3;
1454 }
1455 }
1456 }
1457
1458 return (x-origx);
1459 }
1460
1461 /* draws something of the tower */
1462
1463 /* vert is the vertical position of the tower
1464 * a is the angle on the tower to be drawn: 0 front, 32 right, ...
1465 * angle is the angle of the tower: 0 column 0 in front, 8, column 1, ...
1466 * hs, he are start and ending rows to be drawn
1467 */
putthings(long vert,long a,long angle)1468 static void putthings(long vert, long a, long angle) {
1469
1470 /* ok, at first lets check if there is a column right at the
1471 angle to be drawn */
1472 if (((a - angle) & 0x7) == 0) {
1473
1474 /* yes there is one, find out wich one */
1475 int col = ((a - angle) / TOWER_STEPS_PER_COLUMN) & (TOWER_COLUMNS - 1);
1476
1477 /* calc the x pos where the thing has to be drawn */
1478 int x = sintab[a % TOWER_ANGLES] + (SCREENWID/2);
1479
1480 int slice = 0;
1481 int ypos = SCREENHEI / 2 - SPR_SLICEHEI + vert;
1482
1483 while ((ypos > -SPR_SLICEHEI) && (slice < lev_towerrows())) {
1484
1485 /* if we are over the bottom of the screen, draw the slice */
1486 if (ypos < SCREENHEI)
1487 putcase(lev_tower(slice, col), x, ypos);
1488
1489 slice++;
1490 ypos -= SPR_SLICEHEI;
1491 }
1492 }
1493
1494 /* and now check for robots to be drawn */
1495 for (int rob = 0; rob < 4; rob++) {
1496
1497 /* if the the current robot is active and not the cross */
1498 if (rob_kind(rob) != OBJ_KIND_NOTHING && rob_kind(rob) != OBJ_KIND_CROSS) {
1499
1500 /* ok calc the angle the robots needs to be drawn at */
1501 int rob_a = (rob_angle(rob) - 4 + angle) & (TOWER_ANGLES - 1);
1502
1503 /* check if the robot is "inside" the current column */
1504 if (rob_a > a - 2 && rob_a <= a + 2)
1505 putrobot(rob_kind(rob), rob_time(rob),
1506 sintab[rob_a], SCREENHEI / 2 + vert - rob_vertical(rob) * 4);
1507 }
1508 }
1509 }
1510
putthings_editor(long vert,long a,long angle,int state)1511 static void putthings_editor(long vert, long a, long angle, int state) {
1512
1513 /* ok, at first lets check if there is a column right at the
1514 angle to be drawn */
1515 if (((a - angle) & 0x7) == 0) {
1516
1517 /* yes there is one, find out wich one */
1518 int col = ((a - angle) / TOWER_STEPS_PER_COLUMN) & (TOWER_COLUMNS - 1);
1519
1520 /* calc the x pos where the thing has to be drawn */
1521 int x = sintab[a % TOWER_ANGLES] + (SCREENWID/2);
1522
1523 int slice = 0;
1524 int ypos = SCREENHEI / 2 - SPR_SLICEHEI + vert;
1525
1526 while ((ypos > -SPR_SLICEHEI) && (slice < lev_towerrows())) {
1527
1528 /* if we are over the bottom of the screen, draw the slice */
1529 if (ypos < SCREENHEI)
1530 putcase_editor(lev_tower(slice, col), x, ypos, state);
1531
1532 slice++;
1533 ypos -= SPR_SLICEHEI;
1534 }
1535 }
1536 }
1537
1538 /* draws everything behind the tower */
draw_behind(long vert,long angle)1539 static void draw_behind(long vert, long angle)
1540 {
1541 for (int a = 0; a < 16; a ++) {
1542 /* angle 48 to 31 */
1543 putthings(vert, 48 - a, angle);
1544 /* amgle 80 to 95 */
1545 putthings(vert, 80 + a, angle);
1546 }
1547 }
1548
1549
draw_behind_editor(long vert,long angle,int state)1550 static void draw_behind_editor(long vert, long angle, int state)
1551 {
1552 for (int a = 0; a < 16; a ++) {
1553 putthings_editor(vert, 48 - a, angle, state);
1554 putthings_editor(vert, 80 + a, angle, state);
1555 }
1556 }
1557
1558 /* draws everything in front of the tower */
draw_before(long vert,long angle)1559 static void draw_before(long vert, long angle)
1560 {
1561 for (int a = 0; a < 32; a ++) {
1562 putthings(vert, 32 - a, angle);
1563 putthings(vert, 96 + a, angle);
1564 }
1565 putthings(vert, 0, angle);
1566 }
1567
draw_before_editor(long vert,long angle,int state)1568 static void draw_before_editor(long vert, long angle, int state)
1569 {
1570 for (int a = 0; a < 32; a ++) {
1571 putthings_editor(vert, 32 - a, angle, state);
1572 putthings_editor(vert, 96 + a, angle, state);
1573 }
1574 putthings_editor(vert, 0, angle, state);
1575 }
1576
1577 /* draws the cross that flies over the screen */
putcross(long vert)1578 static void putcross(long vert)
1579 {
1580 long i, y;
1581
1582 for (int t = 0; t < 4; t++) {
1583 if (rob_kind(t) == OBJ_KIND_CROSS) {
1584 i = (rob_angle(t) - 60) * 5;
1585 y = (vert - rob_vertical(t)) * 4 + (SCREENHEI / 2) - SPR_CROSSHEI;
1586 if (y > -SPR_CROSSHEI && y < SCREENHEI)
1587 scr_blit(objectsprites.data(crossst + labs(rob_time(t)) % 120), i + (SCREENWID - SPR_CROSSWID) / 2, y);
1588 return;
1589 }
1590 }
1591 }
1592
1593 /* draws the points, time and lifes left */
draw_data(int time,screenflag flags)1594 static void draw_data(int time, screenflag flags)
1595 {
1596 char s[256];
1597 int t;
1598 int y = config.status_top() ? 5 : SCREENHEI - FONTHEI;
1599
1600 if (time > 0) {
1601 snprintf(s, 256, "%u", time);
1602 scr_writetext_center(y, s);
1603 }
1604
1605 snprintf(s, 256, "%u", pts_points());
1606 scr_writetext(5L, y, s);
1607
1608 *s = '\0';
1609 if (pts_lifes() < 4)
1610 for (t = 0; t < pts_lifes(); t++)
1611 snprintf(s + strlen(s), 256-strlen(s), "%c", fonttoppler);
1612 else snprintf(s, 256, "%ix%c", pts_lifes(), fonttoppler);
1613 scr_writetext(SCREENWID - scr_textlength(s) - 5, y, s);
1614
1615 y = config.status_top() ? SCREENHEI - FONTHEI : 5;
1616 switch (flags) {
1617 case SF_REC: if (!(boxstate & 8)) scr_writetext_center(y, _("REC")); break;
1618 case SF_DEMO: scr_writetext_center(y, _("DEMO")); break;
1619 case SF_NONE:
1620 default: break;
1621 }
1622 }
1623
scr_drawall(long vert,long angle,long time,bool svisible,int subshape,int substart,screenflag flags)1624 void scr_drawall(long vert,
1625 long angle,
1626 long time,
1627 bool svisible,
1628 int subshape,
1629 int substart,
1630 screenflag flags
1631 ) {
1632
1633 cleardesk(vert);
1634
1635 sts_blink();
1636 sts_draw();
1637 draw_behind(vert * 4, angle);
1638 draw_tower(vert * 4, angle);
1639 draw_before(vert * 4, angle);
1640
1641 if (snb_exists())
1642 scr_blit(objectsprites.data(snowballst),
1643 sintab[(snb_anglepos() + angle) % TOWER_ANGLES] + (SCREENWID / 2) - (SPR_HEROWID - SPR_AMMOWID),
1644 ((vert - snb_verticalpos()) * 4) + (SCREENHEI / 2) - SPR_AMMOHEI);
1645
1646 if (top_visible()) {
1647 scr_blit(objectsprites.data(topplerstart + top_shape() +
1648 ((top_look_left()) ? mirror : 0)),
1649 (SCREENWID / 2) - (SPR_HEROWID / 2),
1650 (vert - top_verticalpos()) * 4 + (SCREENHEI / 2) - SPR_HEROHEI);
1651
1652 if (top_onelevator())
1653 scr_blit(restsprites.data((angle % SPR_ELEVAFRAMES) + elevatorsprite), (SCREENWID / 2) - (SPR_ELEVAWID / 2),
1654 vert - top_verticalpos() + (SCREENHEI / 2));
1655 }
1656
1657 if (svisible) {
1658 scr_blit(objectsprites.data(subst + subshape),
1659 (SCREENWID / 2) - 70,
1660 (SCREENHEI / 2) + 12 - substart + 16);
1661
1662 }
1663
1664 putcross(vert);
1665
1666 putbattlement(angle, vert * 4);
1667
1668 putwater(vert);
1669
1670 draw_data(time, flags);
1671
1672 if (dcl_wait_overflow())
1673 scr_putbar(0, 0, 5, 5, 255, 0, 0, 255);
1674
1675 boxstate = (boxstate + 1) & 0xf;
1676 }
1677
scr_drawedit(long vpos,long apos,bool showtime)1678 void scr_drawedit(long vpos, long apos, bool showtime) {
1679
1680 long t;
1681 static long vert = 0, angle = 0;
1682
1683 if (vpos != vert) {
1684 if (vpos > vert) {
1685 if (vpos > vert + 0x8)
1686 vert += 4;
1687 else
1688 vert += 1;
1689 } else {
1690 if (vpos < vert - 0x8)
1691 vert -= 4;
1692 else
1693 vert -= 1;
1694 }
1695 }
1696
1697 apos &= 0x7f;
1698
1699 t = (apos - angle) & (TOWER_ANGLES - 1);
1700
1701 if (t != 0) {
1702 if (t < 0x3f) {
1703 if (t > 0x8)
1704 angle += 4;
1705 else
1706 angle += 1;
1707 } else {
1708 if (t < 0x7f-0x8)
1709 angle -= 4;
1710 else
1711 angle -= 1;
1712 }
1713 angle &= 0x7f;
1714 }
1715
1716 cleardesk(vert);
1717
1718 draw_behind_editor(vert * 4, angle, boxstate);
1719 draw_tower_editor(vert * 4, angle, boxstate);
1720 draw_before_editor(vert * 4, angle, boxstate);
1721
1722 putbattlement(angle, vert * 4);
1723
1724 putwater(vert);
1725
1726 if (boxstate & 1) {
1727 scr_putrect((SCREENWID / 2) - (32 / 2), (SCREENHEI / 2) - 16, 32, 16,
1728 boxstate * 0xf, boxstate *0xf, boxstate *0xf, 128);
1729 }
1730
1731 if (showtime) {
1732 char s[20];
1733 snprintf(s, 20, "%u", lev_towertime());
1734 scr_writetext_center(5, s);
1735 }
1736
1737 boxstate = (boxstate + 1) & 0xf;
1738 }
1739
put_scrollerlayer(long horiz,int layer)1740 static void put_scrollerlayer(long horiz, int layer) {
1741 horiz += scroll_layers[layer].xpos;
1742 horiz %= scroll_layers[layer].xrepeat;
1743 scr_blit(layersprites.data(scroll_layers[layer].image), -horiz, scroll_layers[layer].ypos);
1744 if (horiz + SCREENWID > scroll_layers[layer].xrepeat)
1745 scr_blit(layersprites.data(scroll_layers[layer].image),
1746 scroll_layers[layer].width - horiz, scroll_layers[layer].ypos);
1747 }
1748
scr_draw_bonus1(long horiz,long towerpos)1749 void scr_draw_bonus1(long horiz, long towerpos) {
1750 int l;
1751
1752 if (config.use_full_scroller())
1753 for (l = 0; (l < num_scrolllayers) && (l < sl_tower_depth); l++)
1754 put_scrollerlayer(scroll_layers[l].num*horiz/scroll_layers[l].den, l);
1755 else
1756 put_scrollerlayer(scroll_layers[0].num*horiz/scroll_layers[0].den, 0);
1757
1758 puttower(0, SCREENHEI/2, SCREENHEI, sl_tower_num*towerpos/sl_tower_den);
1759 }
1760
scr_draw_bonus2(long horiz,long towerpos)1761 void scr_draw_bonus2(long horiz, long towerpos) {
1762 int l;
1763
1764 if (config.use_full_scroller())
1765 for (l = sl_tower_depth; l < num_scrolllayers; l++)
1766 put_scrollerlayer(scroll_layers[l].num*horiz/scroll_layers[l].den, l);
1767 else
1768 put_scrollerlayer(scroll_layers[num_scrolllayers-1].num*horiz/scroll_layers[num_scrolllayers-1].den, num_scrolllayers-1);
1769
1770 draw_data(-1, SF_NONE);
1771 }
1772
scr_draw_submarine(long vert,long x,long number)1773 void scr_draw_submarine(long vert, long x, long number) {
1774 scr_blit(objectsprites.data(subst+number), x, vert);
1775 }
1776
scr_draw_fish(long vert,long x,long number)1777 void scr_draw_fish(long vert, long x, long number) {
1778 scr_blit(objectsprites.data(fishst+number), x, vert);
1779 }
1780
scr_draw_torpedo(long vert,long x)1781 void scr_draw_torpedo(long vert, long x) {
1782 scr_blit(objectsprites.data(torb), x, vert);
1783 }
1784