1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
18 /* values for toon animation */
20 #define ANIM_CONTINUE 1
24 static struct ToonScreenInfo screen_info;
27 /* ========================================================================= */
28 /* generic animation frame calculation */
29 /* ========================================================================= */
31 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
36 sync_frame += start_frame * delay;
38 if (mode & ANIM_LOOP) /* looping animation */
40 frame = (sync_frame % (delay * num_frames)) / delay;
42 else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */
44 frame = sync_frame / delay;
46 if (frame > num_frames - 1)
47 frame = num_frames - 1;
49 else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */
51 int max_anim_frames = 2 * num_frames - 2;
53 frame = (sync_frame % (delay * max_anim_frames)) / delay;
54 frame = (frame < num_frames ? frame : max_anim_frames - frame);
56 else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */
58 int max_anim_frames = 2 * num_frames;
60 frame = (sync_frame % (delay * max_anim_frames)) / delay;
61 frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
63 else if (mode & ANIM_RANDOM) /* play frames in random order */
65 /* note: expect different frames for the same delay cycle! */
67 if (gfx.anim_random_frame < 0)
68 frame = SimpleRND(num_frames);
70 frame = gfx.anim_random_frame % num_frames;
73 if (mode & ANIM_REVERSE) /* use reverse animation direction */
74 frame = num_frames - frame - 1;
80 /* ========================================================================= */
81 /* toon animation functions */
82 /* ========================================================================= */
84 static int get_toon_direction(char *direction_raw)
86 static char *direction = NULL;
88 /* !!! MEMORY LEAK HERE! FIX IT! !!! */
89 setString(&direction, getStringToLower(direction_raw));
91 return (strcmp(direction, "left") == 0 ? MV_LEFT :
92 strcmp(direction, "right") == 0 ? MV_RIGHT :
93 strcmp(direction, "up") == 0 ? MV_UP :
94 strcmp(direction, "down") == 0 ? MV_DOWN : MV_NO_MOVING);
97 void InitToonScreen(Bitmap *save_buffer,
98 void (*update_function)(void),
99 void (*prepare_backbuffer_function)(void),
100 boolean (*redraw_needed_function)(void),
101 struct ToonInfo *toons, int num_toons,
102 int startx, int starty,
103 int width, int height,
104 int frame_delay_value)
106 screen_info.save_buffer = save_buffer;
107 screen_info.update_function = update_function;
108 screen_info.prepare_backbuffer_function = prepare_backbuffer_function;
109 screen_info.redraw_needed_function = redraw_needed_function;
110 screen_info.toons = toons;
111 screen_info.num_toons = num_toons;
112 screen_info.startx = startx;
113 screen_info.starty = starty;
114 screen_info.width = width;
115 screen_info.height = height;
116 screen_info.frame_delay_value = frame_delay_value;
119 void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
120 int src_x, int src_y, int width, int height,
121 int dest_x, int dest_y, int pad_x, int pad_y)
123 int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
126 /* special method to avoid flickering interference with BackToFront() */
127 BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
128 width+2*pad_x, height+2*pad_y, buf_x, buf_y);
129 SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x-src_x, dest_y-src_y);
130 BlitBitmapMasked(toon_bitmap, backbuffer,
131 src_x, src_y, width, height, dest_x, dest_y);
132 BlitBitmap(backbuffer, window, dest_x-pad_x, dest_y-pad_y,
133 width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
135 screen_info.update_function();
137 BlitBitmap(screen_info.save_buffer, backbuffer, buf_x, buf_y,
138 width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
140 /* normal method, causing flickering interference with BackToFront() */
141 BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
142 width+2*pad_x, height+2*pad_y, buf_x, buf_y);
143 SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
144 BlitBitmapMasked(toon_bitmap, screen_info.save_buffer,
145 src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
146 BlitBitmap(screen_info.save_buffer, window, buf_x, buf_y,
147 width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
153 boolean AnimateToon(int toon_nr, boolean restart)
155 static unsigned long animation_frame_counter = 0;
156 static int pos_x = 0, pos_y = 0;
157 static int delta_x = 0, delta_y = 0;
158 static int frame = 0;
159 static boolean horiz_move, vert_move;
160 static unsigned long anim_delay = 0;
161 static unsigned long anim_delay_value = 0;
162 static int width,height;
163 static int pad_x,pad_y;
164 static int cut_x,cut_y;
165 static int src_x, src_y;
166 static int dest_x, dest_y;
167 struct ToonInfo *anim = &screen_info.toons[toon_nr];
168 Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap;
169 GC anim_clip_gc = anim_bitmap->stored_clip_gc;
170 int direction = get_toon_direction(anim->direction);
174 horiz_move = (direction & (MV_LEFT | MV_RIGHT));
175 vert_move = (direction & (MV_UP | MV_DOWN));
176 anim_delay_value = anim->step_delay * screen_info.frame_delay_value;
178 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
179 anim->anim_mode, anim->anim_start_frame,
180 animation_frame_counter++);
184 int pos_bottom = screen_info.height - anim->height;
186 if (strcmp(anim->position, "top") == 0)
188 else if (strcmp(anim->position, "bottom") == 0)
190 else if (strcmp(anim->position, "upper") == 0)
191 pos_y = SimpleRND(pos_bottom / 2);
192 else if (strcmp(anim->position, "lower") == 0)
193 pos_y = pos_bottom / 2 + SimpleRND(pos_bottom / 2);
195 pos_y = SimpleRND(pos_bottom);
197 if (direction == MV_RIGHT)
199 delta_x = anim->step_offset;
200 pos_x = -anim->width + delta_x;
204 delta_x = -anim->step_offset;
205 pos_x = screen_info.width + delta_x;
212 int pos_right = screen_info.width - anim->width;
214 if (strcmp(anim->position, "left") == 0)
216 else if (strcmp(anim->position, "right") == 0)
219 pos_x = SimpleRND(pos_right);
221 if (direction == MV_DOWN)
223 delta_y = anim->step_offset;
224 pos_y = -anim->height + delta_y;
228 delta_y = -anim->step_offset;
229 pos_y = screen_info.width + delta_y;
236 if (pos_x <= -anim->width - anim->step_offset ||
237 pos_x >= screen_info.width + anim->step_offset ||
238 pos_y <= -anim->height - anim->step_offset ||
239 pos_y >= screen_info.height + anim->step_offset)
242 if (!DelayReached(&anim_delay, anim_delay_value))
244 if (screen_info.redraw_needed_function() && !restart)
245 DrawAnim(anim_bitmap, anim_clip_gc,
246 src_x + cut_x, src_y + cut_y,
248 screen_info.startx + dest_x,
249 screen_info.starty + dest_y,
255 if (pos_x < -anim->width)
256 pos_x = -anim->width;
257 else if (pos_x > screen_info.width)
258 pos_x = screen_info.width;
259 if (pos_y < -anim->height)
260 pos_y = -anim->height;
261 else if (pos_y > screen_info.height)
262 pos_y = screen_info.height;
264 pad_x = (horiz_move ? anim->step_offset : 0);
265 pad_y = (vert_move ? anim->step_offset : 0);
266 src_x = anim->src_x + frame * anim->width;
272 height = anim->height;
280 else if (pos_x > screen_info.width - anim->width)
281 width -= (pos_x - (screen_info.width - anim->width));
289 else if (pos_y > screen_info.height - anim->height)
290 height -= (pos_y - (screen_info.height - anim->height));
292 DrawAnim(anim_bitmap, anim_clip_gc,
293 src_x + cut_x, src_y + cut_y,
295 screen_info.startx + dest_x,
296 screen_info.starty + dest_y,
302 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
303 anim->anim_mode, anim->anim_start_frame,
304 animation_frame_counter++);
309 void HandleAnimation(int mode)
311 static unsigned long animstart_delay = -1;
312 static unsigned long animstart_delay_value = 0;
313 static boolean anim_running = FALSE;
314 static boolean anim_restart = TRUE;
315 static boolean reset_delay = TRUE;
316 static int toon_nr = 0;
322 /* this may happen after reloading graphics and redefining "num_toons" */
323 if (toon_nr >= screen_info.num_toons)
329 screen_info.prepare_backbuffer_function();
344 redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
346 /* Redraw background even when in direct drawing mode */
347 draw_mode = setup.direct_draw;
348 setup.direct_draw = FALSE;
349 screen_info.update_function();
350 setup.direct_draw = draw_mode;
352 anim_running = FALSE;
362 animstart_delay = Counter();
363 animstart_delay_value = SimpleRND(3000);
369 if (!DelayReached(&animstart_delay, animstart_delay_value))
372 toon_nr = SimpleRND(screen_info.num_toons);
375 anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);
380 HandleAnimation(ANIM_START);
385 HandleAnimation(ANIM_STOP);
390 HandleAnimation(ANIM_CONTINUE);