61683e6c9564c14ef8fa0fce45133b9cc4ffceac
[rocksndiamonds.git] / src / misc.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  misc.c                                                  *
13 ***********************************************************/
14
15 #include "misc.h"
16 #include "tools.h"
17 #include "sound.h"
18 #include <pwd.h>
19 #include <unistd.h>
20 #include <time.h>
21 #include <sys/time.h>
22 #include <sys/param.h>
23 #include <sys/types.h>
24
25 void microsleep(unsigned long usec)
26 {
27   struct timeval delay;
28
29   delay.tv_sec  = usec / 1000000;
30   delay.tv_usec = usec % 1000000;
31
32   if (select(0,NULL,NULL,NULL,&delay)!=0)
33     fprintf(stderr,"%s: in function microsleep: select failed!\n",
34             progname);
35 }
36
37 long mainCounter(int mode)
38 {
39   static struct timeval base_time = { 0, 0 };
40   struct timeval current_time;
41   long counter_ms;
42
43   gettimeofday(&current_time,NULL);
44   if (mode == INIT_COUNTER || current_time.tv_sec < base_time.tv_sec)
45     base_time = current_time;
46
47   counter_ms = (current_time.tv_sec - base_time.tv_sec)*1000
48              + (current_time.tv_usec - base_time.tv_usec)/1000;
49
50   if (mode == READ_COUNTER_100)
51     return(counter_ms/10);      /* return 1/100 secs since last init */
52   else  /*    READ_COUNTER_1000 */
53     return(counter_ms);         /* return 1/1000 secs since last init */
54 }
55
56 void InitCounter() /* set counter back to zero */
57 {
58   mainCounter(INIT_COUNTER);
59 }
60
61 long Counter()  /* returns 1/100 secs since last call of InitCounter() */
62 {
63   return(mainCounter(READ_COUNTER_100));
64 }
65
66 long Counter2() /* returns 1/1000 secs since last call of InitCounter() */
67 {
68   return(mainCounter(READ_COUNTER_1000));
69 }
70
71 void WaitCounter(long value)    /* wait for counter to reach value */
72 {
73   long wait;
74
75   while((wait=value-Counter())>0)
76     microsleep(wait*10000);
77 }
78
79 void WaitCounter2(long value)   /* wait for counter to reach value */
80 {
81   long wait;
82
83   while((wait=value-Counter2())>0)
84     microsleep(wait*1000);
85 }
86
87 void Delay(long value)
88 {
89   microsleep(value);
90 }
91
92 BOOL DelayReached(long *counter_var, int delay)
93 {
94   long actual_counter = Counter();
95
96   if (actual_counter >= *counter_var+delay || actual_counter < *counter_var)
97   {
98     *counter_var = actual_counter;
99     return(TRUE);
100   }
101   else
102     return(FALSE);
103 }
104
105 BOOL FrameReached(long *frame_counter_var, int frame_delay)
106 {
107   long actual_frame_counter = FrameCounter;
108
109   if (actual_frame_counter >= *frame_counter_var+frame_delay
110       || actual_frame_counter < *frame_counter_var)
111   {
112     *frame_counter_var = actual_frame_counter;
113     return(TRUE);
114   }
115   else
116     return(FALSE);
117 }
118
119 unsigned long be2long(unsigned long *be)        /* big-endian -> longword */
120 {
121   unsigned char *ptr = (unsigned char *)be;
122
123   return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
124 }
125
126 char *int2str(int ct, int nr)
127 {
128   static char str[20];
129
130   sprintf(str,"%09d",ct);
131   return(&str[strlen(str)-nr]);
132 }
133
134 unsigned int SimpleRND(unsigned int max)
135 {
136   static unsigned long root = 654321;
137   struct timeval current_time;
138
139   gettimeofday(&current_time,NULL);
140   root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
141   return(root % max);
142 }
143
144 unsigned int RND(unsigned int max)
145 {
146   return(rand() % max);
147 }
148
149 unsigned int InitRND(long seed)
150 {
151   struct timeval current_time;
152
153   if (seed==NEW_RANDOMIZE)
154   {
155     gettimeofday(&current_time,NULL);
156     srand((unsigned int) current_time.tv_usec);
157     return((unsigned int) current_time.tv_usec);
158   }
159   else
160   {
161     srand((unsigned int) seed);
162     return((unsigned int) seed);
163   }
164 }
165
166 char *GetLoginName()
167 {
168   struct passwd *pwd;
169
170   if (!(pwd=getpwuid(getuid())))
171     return("ANONYMOUS");
172   else
173     return(pwd->pw_name);
174 }
175
176 void InitAnimation()
177 {
178   HandleAnimation(ANIM_START);
179 }
180
181 void StopAnimation()
182 {
183   HandleAnimation(ANIM_STOP);
184 }
185
186 void DoAnimation()
187 {
188   HandleAnimation(ANIM_CONTINUE);
189 }
190
191 void HandleAnimation(int mode)
192 {
193   static long animstart_delay = -1;
194   static long animstart_delay_value = 0;
195   static BOOL anim_restart = TRUE;
196   static BOOL reset_delay = TRUE;
197   static int toon_nr = 0;
198   int draw_mode;
199
200 /*
201   if (!toons_on || game_status==PLAYING)
202     return;
203 */
204
205 /*
206   if (!toons_on || tape.playing || tape.recording)
207     return;
208 */
209
210   if (!toons_on)
211     return;
212
213   switch(mode)
214   {
215     case ANIM_START:
216       anim_restart = TRUE;
217       reset_delay = TRUE;
218
219       /* Fill empty backbuffer for animation functions */
220       if (direct_draw_on && game_status==PLAYING)
221       {
222         int xx,yy;
223
224         drawto_field = backbuffer;
225
226         for(xx=0;xx<SCR_FIELDX;xx++)
227           for(yy=0;yy<SCR_FIELDY;yy++)
228             DrawScreenField(xx,yy);
229         DrawLevelElement(JX,JY,EL_SPIELFIGUR);
230
231         drawto_field = window;
232       }
233
234       return;
235       break;
236     case ANIM_CONTINUE:
237       break;
238     case ANIM_STOP:
239       redraw_mask |= REDRAW_FIELD;
240
241       /* Redraw background even when in direct drawing mode */
242       draw_mode = direct_draw_on;
243       direct_draw_on = FALSE;
244
245       BackToFront();
246
247       direct_draw_on = draw_mode;
248
249       return;
250       break;
251     default:
252       break;
253   }
254
255   if (reset_delay)
256   {
257     animstart_delay = Counter();
258     animstart_delay_value = SimpleRND(500);
259     reset_delay = FALSE;
260   }
261
262   if (anim_restart)
263   {
264     if (!DelayReached(&animstart_delay,animstart_delay_value))
265       return;
266
267     toon_nr = SimpleRND(NUM_TOONS);
268   }
269
270   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
271 }
272
273 BOOL AnimateToon(int toon_nr, BOOL restart)
274 {
275   static pos_x = 0, pos_y = 0;
276   static delta_x = 0, delta_y = 0;
277   static int frame = 0, frame_step = 1;
278   static BOOL horiz_move, vert_move;
279   static long anim_delay = 0;
280   static int anim_delay_value = 0;
281   static int width,height;
282   static int pad_x,pad_y;
283   static int cut_x,cut_y;
284   static int src_x, src_y;
285   static int dest_x, dest_y;
286   static struct AnimInfo toon[NUM_TOONS] =
287   {
288    {DWARF_XSIZE, DWARF_YSIZE,
289     DWARF_X, DWARF_Y,
290     DWARF_FRAMES,
291     DWARF_FPS,
292     DWARF_STEPSIZE,
293     FALSE,
294     ANIMDIR_RIGHT,
295     ANIMPOS_DOWN},
296
297    {DWARF_XSIZE, DWARF_YSIZE,
298     DWARF_X, DWARF2_Y,
299     DWARF_FRAMES,
300     DWARF_FPS,
301     DWARF_STEPSIZE,
302     FALSE,
303     ANIMDIR_LEFT,
304     ANIMPOS_DOWN},
305
306    {JUMPER_XSIZE, JUMPER_YSIZE,
307     JUMPER_X, JUMPER_Y,
308     JUMPER_FRAMES,
309     JUMPER_FPS,
310     JUMPER_STEPSIZE,
311     FALSE,
312     ANIMDIR_LEFT,
313     ANIMPOS_DOWN},
314
315    {CLOWN_XSIZE, CLOWN_YSIZE,
316     CLOWN_X, CLOWN_Y,
317     CLOWN_FRAMES,
318     CLOWN_FPS,
319     CLOWN_STEPSIZE,
320     FALSE,
321     ANIMDIR_UP,
322     ANIMPOS_ANY},
323
324    {BIRD_XSIZE, BIRD_YSIZE,
325     BIRD1_X, BIRD1_Y,
326     BIRD_FRAMES,
327     BIRD_FPS,
328     BIRD_STEPSIZE,
329     TRUE,
330     ANIMDIR_RIGHT,
331     ANIMPOS_UPPER},
332
333    {BIRD_XSIZE, BIRD_YSIZE,
334     BIRD2_X, BIRD2_Y,
335     BIRD_FRAMES,
336     BIRD_FPS,
337     BIRD_STEPSIZE,
338     TRUE,
339     ANIMDIR_LEFT,
340     ANIMPOS_UPPER}
341   };
342   struct AnimInfo *anim = &toon[toon_nr];
343
344   if (restart)
345   {
346     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
347     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
348     anim_delay_value = 100/anim->frames_per_second;
349     frame = 0;
350
351     if (horiz_move)
352     {
353       if (anim->position==ANIMPOS_UP)
354         pos_y = 0;
355       else if (anim->position==ANIMPOS_DOWN)
356         pos_y = FULL_SYSIZE-anim->height;
357       else if (anim->position==ANIMPOS_UPPER)
358         pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2);
359       else
360         pos_y = SimpleRND(FULL_SYSIZE-anim->height);
361
362       if (anim->direction==ANIMDIR_RIGHT)
363       {
364         delta_x = anim->stepsize;
365         pos_x = -anim->width+delta_x;
366       }
367       else
368       {
369         delta_x = -anim->stepsize;
370         pos_x = FULL_SXSIZE+delta_x;
371       }
372       delta_y = 0;
373     }
374     else
375     {
376       if (anim->position==ANIMPOS_LEFT)
377         pos_x = 0;
378       else if (anim->position==ANIMPOS_RIGHT)
379         pos_x = FULL_SXSIZE-anim->width;
380       else
381         pos_x = SimpleRND(FULL_SXSIZE-anim->width);
382
383       if (anim->direction==ANIMDIR_DOWN)
384       {
385         delta_y = anim->stepsize;
386         pos_y = -anim->height+delta_y;
387       }
388       else
389       {
390         delta_y = -anim->stepsize;
391         pos_y = FULL_SYSIZE+delta_y;
392       }
393       delta_x = 0;
394     }
395   }
396
397   if (pos_x <= -anim->width  - anim->stepsize ||
398       pos_x >=  FULL_SXSIZE  + anim->stepsize ||
399       pos_y <= -anim->height - anim->stepsize ||
400       pos_y >=  FULL_SYSIZE  + anim->stepsize)
401     return(TRUE);
402
403   if (!DelayReached(&anim_delay,anim_delay_value))
404   {
405     if (game_status==HELPSCREEN && !restart)
406       DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
407                REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
408
409     return(FALSE);
410   }
411
412   if (pos_x<-anim->width)
413     pos_x = -anim->width;
414   else if (pos_x>FULL_SXSIZE)
415     pos_x = FULL_SXSIZE;
416   if (pos_y<-anim->height)
417     pos_y = -anim->height;
418   else if (pos_y>FULL_SYSIZE)
419     pos_y = FULL_SYSIZE;
420
421   pad_x = (horiz_move ? anim->stepsize : 0);
422   pad_y = (vert_move  ? anim->stepsize : 0);
423   src_x = anim->src_x + frame * anim->width;
424   src_y = anim->src_y;
425   dest_x = pos_x;
426   dest_y = pos_y;
427   cut_x = cut_y = 0;
428   width  = anim->width;
429   height = anim->height;
430
431   if (pos_x<0)
432   {
433     dest_x = 0;
434     width += pos_x;
435     cut_x = -pos_x;
436   }
437   else if (pos_x>FULL_SXSIZE-anim->width)
438     width -= (pos_x - (FULL_SXSIZE-anim->width));
439
440   if (pos_y<0)
441   {
442     dest_y = 0;
443     height += pos_y;
444     cut_y = -pos_y;
445   }
446   else if (pos_y>FULL_SYSIZE-anim->height)
447     height -= (pos_y - (FULL_SYSIZE-anim->height));
448
449   DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
450            REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
451
452   pos_x += delta_x;
453   pos_y += delta_y;
454   frame += frame_step;
455
456   if (frame<0 || frame>=anim->frames)
457   {
458     if (anim->pingpong)
459     {
460       frame_step *= -1;
461       frame = (frame<0 ? 1 : anim->frames-2);
462     }
463     else
464       frame = (frame<0 ? anim->frames-1 : 0);
465   }
466
467   return(FALSE);
468 }
469
470 void DrawAnim(int src_x, int src_y, int width, int height,
471               int dest_x, int dest_y, int pad_x, int pad_y)
472 {
473   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
474
475 #if 1
476   /* special method to avoid flickering interference with BackToFront() */
477   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
478             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
479   XSetClipOrigin(display,clip_gc[PIX_TOONS],dest_x-src_x,dest_y-src_y);
480   XCopyArea(display,pix[PIX_TOONS],backbuffer,clip_gc[PIX_TOONS],
481             src_x,src_y, width,height, dest_x,dest_y);
482   XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y,
483             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
484   BackToFront();
485   XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y,
486             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
487 #else
488   /* normal method, causing flickering interference with BackToFront() */
489   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
490             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
491   XSetClipOrigin(display,clip_gc[PIX_TOONS],
492                  buf_x-src_x+pad_x,buf_y-src_y+pad_y);
493   XCopyArea(display,pix[PIX_TOONS],pix[PIX_DB_DOOR],clip_gc[PIX_TOONS],
494             src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y);
495   XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y,
496             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
497 #endif
498
499   XFlush(display);
500 }