1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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 = (num_frames > 1 ? 2 * num_frames - 2 : 1);
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 = GetSimpleRandom(num_frames);
70 frame = gfx.anim_random_frame % num_frames;
72 else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
74 frame = sync_frame % num_frames;
77 if (mode & ANIM_REVERSE) /* use reverse animation direction */
78 frame = num_frames - frame - 1;
84 /* ========================================================================= */
85 /* toon animation functions */
86 /* ========================================================================= */
88 static int get_toon_direction(char *direction_string_raw)
90 char *direction_string = getStringToLower(direction_string_raw);
91 int direction = (strEqual(direction_string, "left") ? MV_LEFT :
92 strEqual(direction_string, "right") ? MV_RIGHT :
93 strEqual(direction_string, "up") ? MV_UP :
94 strEqual(direction_string, "down") ? MV_DOWN :
97 free(direction_string);
102 void InitToonScreen(Bitmap *save_buffer,
103 void (*update_function)(void),
104 void (*prepare_backbuffer_function)(void),
105 boolean (*redraw_needed_function)(void),
106 struct ToonInfo *toons, int num_toons,
107 int startx, int starty,
108 int width, int height,
109 int frame_delay_value)
111 screen_info.save_buffer = save_buffer;
112 screen_info.update_function = update_function;
113 screen_info.prepare_backbuffer_function = prepare_backbuffer_function;
114 screen_info.redraw_needed_function = redraw_needed_function;
115 screen_info.toons = toons;
116 screen_info.num_toons = num_toons;
117 screen_info.startx = startx;
118 screen_info.starty = starty;
119 screen_info.width = width;
120 screen_info.height = height;
121 screen_info.frame_delay_value = frame_delay_value;
124 void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
125 int src_x, int src_y, int width, int height,
126 int dest_x, int dest_y, int pad_x, int pad_y)
128 int pad_dest_x = dest_x - pad_x;
129 int pad_dest_y = dest_y - pad_y;
130 int pad_width = width + 2 * pad_x;
131 int pad_height = height + 2 * pad_y;
136 int buffer_x = DOOR_GFX_PAGEX3;
137 int buffer_y = DOOR_GFX_PAGEY1;
141 printf("::: (%d, %d), (%d, %d), (%d, %d), (%d, %d) -> (%d, %d), (%d, %d), (%d, %d)\n",
147 pad_dest_x, pad_dest_y,
148 pad_width, pad_height,
152 /* correct values to avoid off-screen blitting (start position) */
153 if (pad_dest_x < screen_info.startx)
155 pad_width -= (screen_info.startx - pad_dest_x);
156 pad_dest_x = screen_info.startx;
158 if (pad_dest_y < screen_info.starty)
160 pad_height -= (screen_info.starty - pad_dest_y);
161 pad_dest_y = screen_info.starty;
164 /* correct values to avoid off-screen blitting (blit size) */
165 if (pad_width > screen_info.width)
166 pad_width = screen_info.width;
167 if (pad_height > screen_info.height)
168 pad_height = screen_info.height;
170 /* special method to avoid flickering interference with BackToFront() */
171 BlitBitmap(backbuffer, screen_info.save_buffer, pad_dest_x, pad_dest_y,
172 pad_width, pad_height, buffer_x, buffer_y);
173 SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x - src_x, dest_y - src_y);
174 BlitBitmapMasked(toon_bitmap, backbuffer, src_x, src_y, width, height,
176 BlitBitmap(backbuffer, window, pad_dest_x, pad_dest_y, pad_width, pad_height,
177 pad_dest_x, pad_dest_y);
179 screen_info.update_function();
181 BlitBitmap(screen_info.save_buffer, backbuffer, buffer_x, buffer_y,
182 pad_width, pad_height, pad_dest_x, pad_dest_y);
187 boolean AnimateToon(int toon_nr, boolean restart)
189 static unsigned int animation_frame_counter = 0;
190 static int pos_x = 0, pos_y = 0;
191 static int delta_x = 0, delta_y = 0;
192 static int frame = 0;
193 static boolean horiz_move, vert_move;
194 static unsigned int anim_delay = 0;
195 static unsigned int anim_delay_value = 0;
196 static int width,height;
197 static int pad_x,pad_y;
198 static int cut_x,cut_y;
199 static int src_x, src_y;
200 static int dest_x, dest_y;
201 struct ToonInfo *anim = &screen_info.toons[toon_nr];
202 Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap;
203 GC anim_clip_gc = anim_bitmap->stored_clip_gc;
204 int direction = get_toon_direction(anim->direction);
208 horiz_move = (direction & (MV_LEFT | MV_RIGHT));
209 vert_move = (direction & (MV_UP | MV_DOWN));
210 anim_delay_value = anim->step_delay * screen_info.frame_delay_value;
212 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
213 anim->anim_mode, anim->anim_start_frame,
214 animation_frame_counter++);
218 int pos_bottom = screen_info.height - anim->height;
220 if (strEqual(anim->position, "top"))
222 else if (strEqual(anim->position, "bottom"))
224 else if (strEqual(anim->position, "upper"))
225 pos_y = GetSimpleRandom(pos_bottom / 2);
226 else if (strEqual(anim->position, "lower"))
227 pos_y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
229 pos_y = GetSimpleRandom(pos_bottom);
231 if (direction == MV_RIGHT)
233 delta_x = anim->step_offset;
234 pos_x = -anim->width + delta_x;
238 delta_x = -anim->step_offset;
239 pos_x = screen_info.width + delta_x;
246 int pos_right = screen_info.width - anim->width;
248 if (strEqual(anim->position, "left"))
250 else if (strEqual(anim->position, "right"))
253 pos_x = GetSimpleRandom(pos_right);
255 if (direction == MV_DOWN)
257 delta_y = anim->step_offset;
258 pos_y = -anim->height + delta_y;
262 delta_y = -anim->step_offset;
263 pos_y = screen_info.height + delta_y;
270 if (pos_x <= -anim->width - anim->step_offset ||
271 pos_x >= screen_info.width + anim->step_offset ||
272 pos_y <= -anim->height - anim->step_offset ||
273 pos_y >= screen_info.height + anim->step_offset)
276 if (!DelayReached(&anim_delay, anim_delay_value))
278 if (screen_info.redraw_needed_function() && !restart)
279 DrawAnim(anim_bitmap, anim_clip_gc,
280 src_x + cut_x, src_y + cut_y,
282 screen_info.startx + dest_x,
283 screen_info.starty + dest_y,
289 if (pos_x < -anim->width)
290 pos_x = -anim->width;
291 else if (pos_x > screen_info.width)
292 pos_x = screen_info.width;
293 if (pos_y < -anim->height)
294 pos_y = -anim->height;
295 else if (pos_y > screen_info.height)
296 pos_y = screen_info.height;
298 pad_x = (horiz_move ? anim->step_offset : 0);
299 pad_y = (vert_move ? anim->step_offset : 0);
300 src_x = anim->src_x + frame * anim->width;
306 height = anim->height;
314 else if (pos_x > screen_info.width - anim->width)
315 width -= (pos_x - (screen_info.width - anim->width));
323 else if (pos_y > screen_info.height - anim->height)
324 height -= (pos_y - (screen_info.height - anim->height));
326 DrawAnim(anim_bitmap, anim_clip_gc,
327 src_x + cut_x, src_y + cut_y,
329 screen_info.startx + dest_x,
330 screen_info.starty + dest_y,
336 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
337 anim->anim_mode, anim->anim_start_frame,
338 animation_frame_counter++);
343 void HandleAnimation(int mode)
345 static unsigned int animstart_delay = -1;
346 static unsigned int animstart_delay_value = 0;
347 static boolean anim_running = FALSE;
348 static boolean anim_restart = TRUE;
349 static boolean reset_delay = TRUE;
350 static int toon_nr = 0;
352 if (!setup.toons || screen_info.num_toons == 0)
355 /* this may happen after reloading graphics and redefining "num_toons" */
356 if (toon_nr >= screen_info.num_toons)
362 screen_info.prepare_backbuffer_function();
380 redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
382 screen_info.update_function();
385 anim_running = FALSE;
396 animstart_delay = Counter();
397 animstart_delay_value = GetSimpleRandom(3000);
403 if (!DelayReached(&animstart_delay, animstart_delay_value))
406 toon_nr = GetSimpleRandom(screen_info.num_toons);
409 anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);
414 HandleAnimation(ANIM_START);
419 HandleAnimation(ANIM_STOP);
424 HandleAnimation(ANIM_CONTINUE);