1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
16 static struct ToonScreenInfo screen_info;
19 /* ========================================================================= */
20 /* generic animation frame calculation */
21 /* ========================================================================= */
23 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
28 sync_frame += start_frame * delay;
30 if (mode & ANIM_LOOP) /* looping animation */
32 frame = (sync_frame % (delay * num_frames)) / delay;
34 else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */
36 frame = sync_frame / delay;
38 if (frame > num_frames - 1)
39 frame = num_frames - 1;
41 else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */
43 int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
45 frame = (sync_frame % (delay * max_anim_frames)) / delay;
46 frame = (frame < num_frames ? frame : max_anim_frames - frame);
48 else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */
50 int max_anim_frames = 2 * num_frames;
52 frame = (sync_frame % (delay * max_anim_frames)) / delay;
53 frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
55 else if (mode & ANIM_RANDOM) /* play frames in random order */
57 /* note: expect different frames for the same delay cycle! */
59 if (gfx.anim_random_frame < 0)
60 frame = GetSimpleRandom(num_frames);
62 frame = gfx.anim_random_frame % num_frames;
64 else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
66 frame = sync_frame % num_frames;
69 if (mode & ANIM_REVERSE) /* use reverse animation direction */
70 frame = num_frames - frame - 1;
76 /* ========================================================================= */
77 /* toon animation functions */
78 /* ========================================================================= */
80 static int get_toon_direction(char *direction_string_raw)
82 char *direction_string = getStringToLower(direction_string_raw);
83 int direction = (strEqual(direction_string, "left") ? MV_LEFT :
84 strEqual(direction_string, "right") ? MV_RIGHT :
85 strEqual(direction_string, "up") ? MV_UP :
86 strEqual(direction_string, "down") ? MV_DOWN :
89 free(direction_string);
94 void InitToonScreen(Bitmap *save_buffer,
95 void (*update_function)(void),
96 void (*prepare_backbuffer_function)(void),
97 boolean (*redraw_needed_function)(void),
98 struct ToonInfo *toons, int num_toons,
99 int startx, int starty,
100 int width, int height,
101 int frame_delay_value)
103 screen_info.save_buffer = save_buffer;
104 screen_info.update_function = update_function;
105 screen_info.prepare_backbuffer_function = prepare_backbuffer_function;
106 screen_info.redraw_needed_function = redraw_needed_function;
107 screen_info.toons = toons;
108 screen_info.num_toons = num_toons;
109 screen_info.startx = startx;
110 screen_info.starty = starty;
111 screen_info.width = width;
112 screen_info.height = height;
113 screen_info.frame_delay_value = frame_delay_value;
116 void DrawAnim(Bitmap *toon_bitmap, int src_x, int src_y, int width, int height,
117 int dest_x, int dest_y, int pad_x, int pad_y)
119 int pad_dest_x = dest_x - pad_x;
120 int pad_dest_y = dest_y - pad_y;
121 int pad_width = width + 2 * pad_x;
122 int pad_height = height + 2 * pad_y;
126 /* correct values to avoid off-screen blitting (start position) */
127 if (pad_dest_x < screen_info.startx)
129 pad_width -= (screen_info.startx - pad_dest_x);
130 pad_dest_x = screen_info.startx;
132 if (pad_dest_y < screen_info.starty)
134 pad_height -= (screen_info.starty - pad_dest_y);
135 pad_dest_y = screen_info.starty;
138 /* correct values to avoid off-screen blitting (blit size) */
139 if (pad_width > screen_info.width)
140 pad_width = screen_info.width;
141 if (pad_height > screen_info.height)
142 pad_height = screen_info.height;
144 /* special method to avoid flickering interference with BackToFront() */
145 BlitBitmap(backbuffer, screen_info.save_buffer, pad_dest_x, pad_dest_y,
146 pad_width, pad_height, buffer_x, buffer_y);
147 BlitBitmapMasked(toon_bitmap, backbuffer, src_x, src_y, width, height,
149 BlitBitmap(backbuffer, window, pad_dest_x, pad_dest_y, pad_width, pad_height,
150 pad_dest_x, pad_dest_y);
152 screen_info.update_function();
154 BlitBitmap(screen_info.save_buffer, backbuffer, buffer_x, buffer_y,
155 pad_width, pad_height, pad_dest_x, pad_dest_y);
157 /* prevent immediate redraw of restored toon area in backbuffer */
158 redraw_mask = REDRAW_NONE;
161 boolean AnimateToon(int toon_nr, boolean restart)
163 static unsigned int animation_frame_counter = 0;
164 static int pos_x = 0, pos_y = 0;
165 static int delta_x = 0, delta_y = 0;
166 static int frame = 0;
167 static boolean horiz_move, vert_move;
168 static unsigned int anim_delay = 0;
169 static unsigned int anim_delay_value = 0;
170 static int width,height;
171 static int pad_x,pad_y;
172 static int cut_x,cut_y;
173 static int src_x, src_y;
174 static int dest_x, dest_y;
175 struct ToonInfo *anim = &screen_info.toons[toon_nr];
176 Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap;
177 int direction = get_toon_direction(anim->direction);
181 horiz_move = (direction & (MV_LEFT | MV_RIGHT));
182 vert_move = (direction & (MV_UP | MV_DOWN));
183 anim_delay_value = anim->step_delay * screen_info.frame_delay_value;
185 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
186 anim->anim_mode, anim->anim_start_frame,
187 animation_frame_counter++);
191 int pos_bottom = screen_info.height - anim->height;
193 if (strEqual(anim->position, "top"))
195 else if (strEqual(anim->position, "bottom"))
197 else if (strEqual(anim->position, "upper"))
198 pos_y = GetSimpleRandom(pos_bottom / 2);
199 else if (strEqual(anim->position, "lower"))
200 pos_y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
202 pos_y = GetSimpleRandom(pos_bottom);
204 if (direction == MV_RIGHT)
206 delta_x = anim->step_offset;
207 pos_x = -anim->width + delta_x;
211 delta_x = -anim->step_offset;
212 pos_x = screen_info.width + delta_x;
219 int pos_right = screen_info.width - anim->width;
221 if (strEqual(anim->position, "left"))
223 else if (strEqual(anim->position, "right"))
226 pos_x = GetSimpleRandom(pos_right);
228 if (direction == MV_DOWN)
230 delta_y = anim->step_offset;
231 pos_y = -anim->height + delta_y;
235 delta_y = -anim->step_offset;
236 pos_y = screen_info.height + delta_y;
243 if (pos_x <= -anim->width - anim->step_offset ||
244 pos_x >= screen_info.width + anim->step_offset ||
245 pos_y <= -anim->height - anim->step_offset ||
246 pos_y >= screen_info.height + anim->step_offset)
249 if (!DelayReached(&anim_delay, anim_delay_value))
251 if (screen_info.redraw_needed_function() && !restart)
252 DrawAnim(anim_bitmap,
253 src_x + cut_x, src_y + cut_y,
255 screen_info.startx + dest_x,
256 screen_info.starty + dest_y,
262 if (pos_x < -anim->width)
263 pos_x = -anim->width;
264 else if (pos_x > screen_info.width)
265 pos_x = screen_info.width;
266 if (pos_y < -anim->height)
267 pos_y = -anim->height;
268 else if (pos_y > screen_info.height)
269 pos_y = screen_info.height;
271 pad_x = (horiz_move ? anim->step_offset : 0);
272 pad_y = (vert_move ? anim->step_offset : 0);
273 src_x = anim->src_x + frame * anim->width;
279 height = anim->height;
287 else if (pos_x > screen_info.width - anim->width)
288 width -= (pos_x - (screen_info.width - anim->width));
296 else if (pos_y > screen_info.height - anim->height)
297 height -= (pos_y - (screen_info.height - anim->height));
299 DrawAnim(anim_bitmap,
300 src_x + cut_x, src_y + cut_y,
302 screen_info.startx + dest_x,
303 screen_info.starty + dest_y,
309 frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
310 anim->anim_mode, anim->anim_start_frame,
311 animation_frame_counter++);
316 void HandleAnimation(int mode)
318 static unsigned int animstart_delay = -1;
319 static unsigned int animstart_delay_value = 0;
320 static boolean anim_running = FALSE;
321 static boolean anim_restart = TRUE;
322 static boolean reset_delay = TRUE;
323 static int toon_nr = 0;
325 if (!setup.toons || screen_info.num_toons == 0)
328 /* this may happen after reloading graphics and redefining "num_toons" */
329 if (toon_nr >= screen_info.num_toons)
335 screen_info.prepare_backbuffer_function();
352 redraw_mask |= REDRAW_FIELD;
354 screen_info.update_function();
356 anim_running = FALSE;
367 animstart_delay = Counter();
368 animstart_delay_value = GetSimpleRandom(3000);
374 if (!DelayReached(&animstart_delay, animstart_delay_value))
377 toon_nr = GetSimpleRandom(screen_info.num_toons);
380 anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);