a17b1da5f12834dd4406b13bf268eb70a4ba4009
[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==0 || 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==1)
51     return(counter_ms/10);      /* return 1/100 secs since last init */
52   else
53     return(counter_ms);         /* return 1/1000 secs since last init */
54 }
55
56 void InitCounter() /* set counter back to zero */
57 {
58   mainCounter(0);
59 }
60
61 long Counter()  /* returns 1/100 secs since last call of InitCounter() */
62 {
63   return(mainCounter(1));
64 }
65
66 long Counter2() /* returns 1/1000 secs since last call of InitCounter() */
67 {
68   return(mainCounter(2));
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 unsigned long be2long(unsigned long *be)        /* big-endian -> longword */
106 {
107   unsigned char *ptr = (unsigned char *)be;
108
109   return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
110 }
111
112 char *int2str(int ct, int nr)
113 {
114   static char str[20];
115
116   sprintf(str,"%09d",ct);
117   return(&str[strlen(str)-nr]);
118 }
119
120 unsigned int RND(unsigned int max)
121 {
122   return(rand() % max);
123 }
124
125 unsigned int InitRND(long seed)
126 {
127   struct timeval current_time;
128
129   if (seed==NEW_RANDOMIZE)
130   {
131     gettimeofday(&current_time,NULL);
132     srand((unsigned int) current_time.tv_usec);
133     return((unsigned int) current_time.tv_usec);
134   }
135   else
136   {
137     srand((unsigned int) seed);
138     return((unsigned int) seed);
139   }
140 }
141
142 char *GetLoginName()
143 {
144   struct passwd *pwd;
145
146   if (!(pwd=getpwuid(getuid())))
147     return("ANONYMOUS");
148   else
149     return(pwd->pw_name);
150 }
151
152 void InitAnimation()
153 {
154   HandleAnimation(ANIM_START);
155 }
156
157 void StopAnimation()
158 {
159   HandleAnimation(ANIM_STOP);
160 }
161
162 void DoAnimation()
163 {
164   HandleAnimation(ANIM_CONTINUE);
165 }
166
167 void HandleAnimation(int mode)
168 {
169   static long animstart_delay = -1;
170   static long animstart_delay_value = 0;
171   static BOOL anim_restart = TRUE;
172   static BOOL reset_delay = TRUE;
173   static int toon_nr = 0;
174
175   if (!toons_on || game_status==PLAYING)
176     return;
177
178   switch(mode)
179   {
180     case ANIM_START:
181       anim_restart = TRUE;
182       reset_delay = TRUE;
183       return;
184       break;
185     case ANIM_CONTINUE:
186       break;
187     case ANIM_STOP:
188       redraw_mask |= REDRAW_FIELD;
189       BackToFront();
190       return;
191       break;
192     default:
193       break;
194   }
195
196   if (reset_delay)
197   {
198     animstart_delay = Counter();
199     animstart_delay_value = RND(500);
200     reset_delay = FALSE;
201   }
202
203   if (anim_restart)
204   {
205     if (!DelayReached(&animstart_delay,animstart_delay_value))
206       return;
207
208     toon_nr = RND(NUM_TOONS);
209   }
210
211   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
212 }
213
214 BOOL AnimateToon(int toon_nr, BOOL restart)
215 {
216   static pos_x = 0, pos_y = 0;
217   static delta_x = 0, delta_y = 0;
218   static int frame = 0, frame_step = 1;
219   static BOOL horiz_move, vert_move;
220   static long anim_delay = 0;
221   static int anim_delay_value = 0;
222   static int width,height;
223   static int pad_x,pad_y;
224   static int cut_x,cut_y;
225   static int src_x, src_y;
226   static int dest_x, dest_y;
227   static struct AnimInfo toon[NUM_TOONS] =
228   {
229     DWARF_XSIZE, DWARF_YSIZE,
230     DWARF_X, DWARF_Y,
231     DWARF_FRAMES,
232     DWARF_FPS,
233     DWARF_STEPSIZE,
234     FALSE,
235     ANIMDIR_RIGHT,
236     ANIMPOS_DOWN,
237
238     DWARF_XSIZE, DWARF_YSIZE,
239     DWARF_X, DWARF2_Y,
240     DWARF_FRAMES,
241     DWARF_FPS,
242     DWARF_STEPSIZE,
243     FALSE,
244     ANIMDIR_LEFT,
245     ANIMPOS_DOWN,
246
247     JUMPER_XSIZE, JUMPER_YSIZE,
248     JUMPER_X, JUMPER_Y,
249     JUMPER_FRAMES,
250     JUMPER_FPS,
251     JUMPER_STEPSIZE,
252     FALSE,
253     ANIMDIR_LEFT,
254     ANIMPOS_DOWN,
255
256     CLOWN_XSIZE, CLOWN_YSIZE,
257     CLOWN_X, CLOWN_Y,
258     CLOWN_FRAMES,
259     CLOWN_FPS,
260     CLOWN_STEPSIZE,
261     FALSE,
262     ANIMDIR_UP,
263     ANIMPOS_ANY,
264
265     BIRD_XSIZE, BIRD_YSIZE,
266     BIRD1_X, BIRD1_Y,
267     BIRD_FRAMES,
268     BIRD_FPS,
269     BIRD_STEPSIZE,
270     TRUE,
271     ANIMDIR_RIGHT,
272     ANIMPOS_UPPER,
273
274     BIRD_XSIZE, BIRD_YSIZE,
275     BIRD2_X, BIRD2_Y,
276     BIRD_FRAMES,
277     BIRD_FPS,
278     BIRD_STEPSIZE,
279     TRUE,
280     ANIMDIR_LEFT,
281     ANIMPOS_UPPER
282   };
283   struct AnimInfo *anim = &toon[toon_nr];
284
285   if (restart)
286   {
287     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
288     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
289     anim_delay_value = 100/anim->frames_per_second;
290     frame = 0;
291
292     if (horiz_move)
293     {
294       if (anim->position==ANIMPOS_UP)
295         pos_y = 0;
296       else if (anim->position==ANIMPOS_DOWN)
297         pos_y = FULL_SYSIZE-anim->height;
298       else if (anim->position==ANIMPOS_UPPER)
299         pos_y = RND((FULL_SYSIZE-anim->height)/2);
300       else
301         pos_y = RND(FULL_SYSIZE-anim->height);
302
303       if (anim->direction==ANIMDIR_RIGHT)
304       {
305         delta_x = anim->stepsize;
306         pos_x = -anim->width+delta_x;
307       }
308       else
309       {
310         delta_x = -anim->stepsize;
311         pos_x = FULL_SXSIZE+delta_x;
312       }
313       delta_y = 0;
314     }
315     else
316     {
317       if (anim->position==ANIMPOS_LEFT)
318         pos_x = 0;
319       else if (anim->position==ANIMPOS_RIGHT)
320         pos_x = FULL_SXSIZE-anim->width;
321       else
322         pos_x = RND(FULL_SXSIZE-anim->width);
323
324       if (anim->direction==ANIMDIR_DOWN)
325       {
326         delta_y = anim->stepsize;
327         pos_y = -anim->height+delta_y;
328       }
329       else
330       {
331         delta_y = -anim->stepsize;
332         pos_y = FULL_SYSIZE+delta_y;
333       }
334       delta_x = 0;
335     }
336   }
337
338   if (pos_x <= -anim->width  - anim->stepsize ||
339       pos_x >=  FULL_SXSIZE  + anim->stepsize ||
340       pos_y <= -anim->height - anim->stepsize ||
341       pos_y >=  FULL_SYSIZE  + anim->stepsize)
342     return(TRUE);
343
344   if (!DelayReached(&anim_delay,anim_delay_value))
345   {
346     if (game_status==HELPSCREEN && !restart)
347       DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
348                REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
349
350     return(FALSE);
351   }
352
353   if (pos_x<-anim->width)
354     pos_x = -anim->width;
355   else if (pos_x>FULL_SXSIZE)
356     pos_x = FULL_SXSIZE;
357   if (pos_y<-anim->height)
358     pos_y = -anim->height;
359   else if (pos_y>FULL_SYSIZE)
360     pos_y = FULL_SYSIZE;
361
362   pad_x = (horiz_move ? anim->stepsize : 0);
363   pad_y = (vert_move  ? anim->stepsize : 0);
364   src_x = anim->src_x + frame * anim->width;
365   src_y = anim->src_y;
366   dest_x = pos_x;
367   dest_y = pos_y;
368   cut_x = cut_y = 0;
369   width  = anim->width;
370   height = anim->height;
371
372   if (pos_x<0)
373   {
374     dest_x = 0;
375     width += pos_x;
376     cut_x = -pos_x;
377   }
378   else if (pos_x>FULL_SXSIZE-anim->width)
379     width -= (pos_x - (FULL_SXSIZE-anim->width));
380
381   if (pos_y<0)
382   {
383     dest_y = 0;
384     height += pos_y;
385     cut_y = -pos_y;
386   }
387   else if (pos_y>FULL_SYSIZE-anim->height)
388     height -= (pos_y - (FULL_SYSIZE-anim->height));
389
390   DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
391            REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
392
393   pos_x += delta_x;
394   pos_y += delta_y;
395   frame += frame_step;
396
397   if (frame<0 || frame>=anim->frames)
398   {
399     if (anim->pingpong)
400     {
401       frame_step *= -1;
402       frame = (frame<0 ? 1 : anim->frames-2);
403     }
404     else
405       frame = (frame<0 ? anim->frames-1 : 0);
406   }
407
408   return(FALSE);
409 }
410
411 void DrawAnim(int src_x, int src_y, int width, int height,
412               int dest_x, int dest_y, int pad_x, int pad_y)
413 {
414   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
415
416 #if 1
417   /* special method to avoid flickering interference with BackToFront() */
418   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
419             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
420   XSetClipOrigin(display,clip_gc[PIX_TOONS],dest_x-src_x,dest_y-src_y);
421   XCopyArea(display,pix[PIX_TOONS],backbuffer,clip_gc[PIX_TOONS],
422             src_x,src_y, width,height, dest_x,dest_y);
423   XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y,
424             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
425   BackToFront();
426   XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y,
427             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
428 #else
429   /* normal method, causing flickering interference with BackToFront() */
430   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
431             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
432   XSetClipOrigin(display,clip_gc[PIX_TOONS],
433                  buf_x-src_x+pad_x,buf_y-src_y+pad_y);
434   XCopyArea(display,pix[PIX_TOONS],pix[PIX_DB_DOOR],clip_gc[PIX_TOONS],
435             src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y);
436   XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y,
437             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
438 #endif
439
440   XFlush(display);
441 }