1 /**************************************************************************
2 practice.c
3 - description: practice module
4 -------------------
5 begin : Friday Jan 25, 2003
6 copyright : (C) 2003 by Jesse Andrews
7 email : jdandr2@uky.edu
8
9 Revised extensively: 2007 and 2008
10 David Bruce <davidstuartbruce@gmail.com>
11 Revised extensively: 2008
12 Sreyas Kurumanghat <k.sreyas@gmail.com>
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24 #include "globals.h"
25 #include "funcs.h"
26 #include "SDL_extras.h"
27 #include "convert_utf.h"
28
29 #define MAX_PHRASES 256
30 #define MAX_PHRASE_LENGTH 256
31 #define MAX_WRAP_LINES 10
32 #define TEXT_HEIGHT 28
33 #define SPRITE_FRAME_TIME 200
34 /* "Local globals" for practice.c */
35 static int fontsize = 0;
36 static int medfontsize = 0;
37 static int bigfontsize = 0;
38
39 /* Surfaces for things we want to pre-render: */
40 static SDL_Surface* hands = NULL;
41 static SDL_Surface* hand_shift[3] = {NULL};
42 static SDL_Surface* keyboard = NULL;
43 static SDL_Surface* keypress1 = NULL;
44 static SDL_Surface* keypress2 = NULL;
45 static SDL_Surface* hand[11] = {NULL};
46 static sprite* tux_stand = NULL;
47 static sprite* tux_win = NULL;
48 static SDL_Surface* time_label_srfc = NULL;
49 static SDL_Surface* chars_label_srfc = NULL;
50 static SDL_Surface* cpm_label_srfc = NULL;
51 static SDL_Surface* wpm_label_srfc = NULL;
52 static SDL_Surface* errors_label_srfc = NULL;
53 static SDL_Surface* accuracy_label_srfc = NULL;
54
55
56 static wchar_t phrases[MAX_PHRASES][MAX_PHRASE_LENGTH];
57 static Mix_Chunk* wrong = NULL;
58 static Mix_Chunk* cheer = NULL;
59
60
61 static int phrase_draw_width = 0; /* How wide before text needs wrapping */
62 static int num_phrases = 0;
63
64
65 /* Locations for blitting */
66
67 /* Three main areas within window: */
68 static SDL_Rect left_pane;
69 static SDL_Rect top_pane;
70 static SDL_Rect bottom_pane;
71
72 /* Locations within left pane: */
73 static SDL_Rect tux_loc;
74 static SDL_Rect time_label;
75 static SDL_Rect time_rect;
76 static SDL_Rect chars_typed_label;
77 static SDL_Rect chars_typed_rect;
78 static SDL_Rect cpm_label;
79 static SDL_Rect cpm_rect;
80 static SDL_Rect wpm_label;
81 static SDL_Rect wpm_rect;
82 static SDL_Rect errors_label;
83 static SDL_Rect errors_rect;
84 static SDL_Rect accuracy_label;
85 static SDL_Rect accuracy_rect;
86
87 /* Locations within top pane: */
88 static SDL_Rect phr_text_rect;
89 static SDL_Rect user_text_rect;
90
91 /* Locations within bottom pane: */
92 static SDL_Rect hand_loc;
93 static SDL_Rect nextletter_rect;
94 //static SDL_Rect letter_loc;
95 static SDL_Rect keyboard_loc;
96
97
98 /*local function prototypes: */
99 static int load_phrases(const char* phrase_file);
100 static int find_next_wrap(const wchar_t* wstr, int font_size, int width);
101 static void recalc_positions(void);
102 static void calc_font_sizes(void);
103 static int create_labels(void);
104 static void display_next_letter(const wchar_t* str, Uint16 index);
105 static int practice_load_media(void);
106 static void practice_unload_media(void);
107 //static void show(char t);
108 SDL_Surface* GetKeypress1(int index);
109 SDL_Surface* GetKeypress2(int index);
110 SDL_Surface* GetWrongKeypress(int index);
111 static void print_load_results(void);
112
113 /************************************************************************/
114 /* */
115 /* "Public" functions (callable throughout program) */
116 /* */
117 /************************************************************************/
118
119 /* -------- This is the main function for the 'Practice' activity. ------ */
Phrases(wchar_t * pphrase)120 int Phrases(wchar_t* pphrase )
121 {
122 /* FIXME make variable names more descriptive */
123 Uint32 start = 0, a = 0, tuxtime = 0;
124 int quit = 0,
125 i = 0,
126 cursor = 0,
127 wrap_pt = 0,
128 prev_wrap = 0,
129 total = 0,
130 state = 0;
131 int once_only = 0;
132 int correct_chars = 0;
133 int wrong_chars = 0;
134 float accuracy = 0;
135 int cur_phrase = 0;
136 int keytimes[MAX_PHRASE_LENGTH] = {0};
137 char time_str[20];
138 char chars_typed_str[20];
139 char cpm_str[20];
140 char wpm_str[20];
141 char errors_str[20];
142 char accuracy_str[20];
143 SDL_Surface* tmpsurf = NULL;
144
145 /* Load all needed graphics, strings, sounds.... */
146 if (!practice_load_media())
147 {
148 fprintf(stderr, "Phrases() - practice_load_media() failed, returning.\n\n");
149 return 0;
150 }
151
152 /* If we got a phrase string arg, use it, otherwise we */
153 /* load practice phrases from the default file: */
154 if (pphrase != NULL
155 && wcslen(pphrase) > 0)
156 {
157 wcsncpy(phrases[0], pphrase, MAX_PHRASE_LENGTH);
158 num_phrases = 1;
159 once_only = 1;
160 }
161 else
162 {
163 num_phrases = load_phrases("phrases.txt");
164 }
165 /* Set up positions for blitting: */
166 recalc_positions();
167
168 start = tuxtime = SDL_GetTicks();
169
170
171 /* Begin main event loop for "Practice" activity: -------- */
172 do
173 {
174 switch (state)
175 {
176 /* state = 0 means the phrase has changed and we need to reset */
177 /* all the variables related to progress of this phrase; we also */
178 /* need a complete redraw (state = 1) */
179 case 0:
180 /* reset other variables related to progress within phrase: */
181 for (i = 0; i < MAX_PHRASE_LENGTH; i++)
182 keytimes[i] = 0;
183 time_str[0] = '\0';
184 chars_typed_str[0] = '\0';
185 cpm_str[0] = '\0';
186 wpm_str[0] = '\0';
187 errors_str[0] = '\0';
188 accuracy_str[0] = '\0';
189 total = 0;
190 cursor = 0;
191 wrap_pt = 0;
192 prev_wrap = 0;
193 correct_chars = 0;
194 wrong_chars = 0;
195 /* No 'break;' so we drop through to do case 1 as well : */
196
197 /* state == 1 means complete redraw needed */
198 /* If we do this without the case 0 resets, it means the wrap point */
199 /* has changed and the text needs redrawing, or that the screen */
200 /* size has changed: */
201 case 1:
202 /* Draw bkgd before we start */
203 /* NOTE the keyboard and hands will get drawn when we drop through to case 2: */
204 SDL_BlitSurface(CurrentBkgd(), NULL, screen, NULL);
205 /* Note - the validity of all these surfaces is tested */
206 /* in Practice_Load_Media(), so we should be safe. */
207
208 /* Draw Tux: */
209 SDL_BlitSurface(tux_stand->frame[tux_stand->cur], NULL, screen, &tux_loc);
210 /* Draw all the labels for the typing stats: */
211 SDL_BlitSurface(time_label_srfc, NULL, screen, &time_label);
212 SDL_BlitSurface(chars_label_srfc, NULL, screen, &chars_typed_label);
213 SDL_BlitSurface(cpm_label_srfc, NULL, screen, &cpm_label);
214 SDL_BlitSurface(wpm_label_srfc, NULL, screen, &wpm_label);
215 SDL_BlitSurface(errors_label_srfc, NULL, screen, &errors_label);
216 SDL_BlitSurface(accuracy_label_srfc, NULL, screen, &accuracy_label);
217
218
219 /* Find wrapping point: */
220 wrap_pt = find_next_wrap(&phrases[cur_phrase][prev_wrap],
221 medfontsize, phrase_draw_width);
222
223 /* Draw the phrase to be typed up to the next wrapping point: */
224 DEBUGCODE
225 {
226 wchar_t buf[200];
227 wcsncpy(buf, &phrases[cur_phrase][prev_wrap], wrap_pt + 1);
228 buf[wrap_pt + 1]= '\0';
229 fprintf(stderr, "wrap_pt = %d\t cursor = %d\t prev_wrap = %d\n",
230 wrap_pt, cursor, prev_wrap);
231 fprintf(stderr, "Phrase to be typed is: %S\n", buf);
232 }
233
234 tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
235 medfontsize, &white, wrap_pt + 1);
236
237 if (tmpsurf)
238 {
239 SDL_BlitSurface(tmpsurf, NULL, screen, &phr_text_rect);
240 SDL_FreeSurface(tmpsurf);
241 tmpsurf = NULL;
242 }
243
244 /* Draw the text the player has typed so far: */
245
246 tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
247 medfontsize, &white,
248 cursor - prev_wrap);
249
250 DEBUGCODE
251 {
252 wchar_t buf[200];
253 wcsncpy(buf, &phrases[cur_phrase][prev_wrap], cursor - prev_wrap);
254 buf[cursor - prev_wrap]= '\0';
255 fprintf(stderr, "wrap_pt = %d\t cursor = %d\t prev_wrap = %d\n",
256 wrap_pt, cursor, prev_wrap);
257 fprintf(stderr, "Text typed so far is: %S\n", buf);
258 }
259
260 if (tmpsurf)
261 {
262 SDL_BlitSurface(tmpsurf, NULL, screen, &user_text_rect);
263 SDL_FreeSurface(tmpsurf);
264 tmpsurf = NULL;
265 }
266
267 /* Update timer: */
268 tmpsurf = BlackOutline(time_str, fontsize, &white);
269 if (tmpsurf)
270 {
271 SDL_BlitSurface(tmpsurf, NULL, screen, &time_rect);
272 SDL_FreeSurface(tmpsurf);
273 tmpsurf = NULL;
274 }
275
276 /* state == 2 means user has pressed key, either correct or incorrect */
277 case 2:
278 start = SDL_GetTicks();
279 SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
280 SDL_BlitSurface(hands, NULL, screen, &hand_loc);
281 SDL_BlitSurface(keyboard, NULL, screen, &keyboard_loc);
282 /* Update entire screen */
283 SDL_UpdateRect(screen, 0, 0, 0, 0);
284
285 state = 3;
286 break;
287
288
289 case 3: /* Wind up here the next time through the loop: */
290 /* If no typing for 0.5 sec, display hint: */
291 if (SDL_GetTicks() - start > 500)
292 {
293
294 /* Show finger hint, if available. Note that GetFinger() */
295 /* returns negative values on error and never returns a */
296 /* value greater than 9. */
297 int key = GetIndex(phrases[cur_phrase][cursor]);
298 int fing = GetFinger(key);
299 int shift = GetShift(key);
300 keypress1 = GetKeypress1(key);
301 keypress2 = GetKeypress2(key);
302
303 SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
304 SDL_BlitSurface(hands, NULL, screen, &hand_loc);
305
306 if (fing >= 0)
307 SDL_BlitSurface(hand[fing], NULL, screen, &hand_loc);
308 SDL_BlitSurface(hand_shift[shift], NULL, screen, &hand_loc);
309
310 if (keypress1)
311 {
312 SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
313 SDL_FreeSurface(keypress1);
314 keypress1 = NULL;
315 }
316
317 if (keypress2)
318 {
319 SDL_BlitSurface(keypress2, NULL, screen, &keyboard_loc);
320 SDL_FreeSurface(keypress2);
321 keypress2 = NULL;
322 }
323
324 state = 4;
325 }
326 break;
327
328 case 4:
329 /* After 0.75 sec, hint starts flashing (alternating states 5 and 6 with delays) */
330 if (SDL_GetTicks() - start > 750)
331 {
332 state = 5;
333 }
334 break;
335
336 case 5:
337 SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
338 SDL_BlitSurface(hands, NULL, screen, &hand_loc);
339 SDL_BlitSurface(keyboard, NULL, screen, &keyboard_loc);
340 state = 14;
341 break;
342
343 case 6:
344 {
345 int key = GetIndex(phrases[cur_phrase][cursor]);
346 int fing = GetFinger(key);
347 int shift = GetShift(key);
348 keypress1 = GetKeypress1(key);
349 keypress2 = GetKeypress2(key);
350
351 SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
352 SDL_BlitSurface(hands, NULL, screen, &hand_loc);
353
354 if (fing >= 0)
355 SDL_BlitSurface(hand[fing], NULL, screen, &hand_loc);
356
357 SDL_BlitSurface(hand_shift[shift], NULL, screen, &hand_loc);
358
359 if (keypress1)
360 {
361 SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
362 SDL_FreeSurface(keypress1);
363 keypress1 = NULL;
364 }
365
366 if (keypress2)
367 {
368 SDL_BlitSurface(keypress2, NULL, screen, &keyboard_loc);
369 SDL_FreeSurface(keypress2);
370 keypress2 = NULL;
371 }
372
373 state = 13;
374 break;
375 }
376
377 default:
378 state -= 2; // this is to make the flashing slower
379
380 } /* ----------- End of switch(state) statement-------------- */
381
382 /* This blits the next character onto the screen in a large font: */
383 display_next_letter(phrases[cur_phrase], cursor);
384
385 while (SDL_PollEvent(&event))
386 {
387 if (event.type == SDL_KEYDOWN)
388 {
389 int key = GetIndex((wchar_t)event.key.keysym.unicode);
390 int shift_pressed = event.key.keysym.mod&KMOD_SHIFT;
391 char tmp = -1;
392
393 /* TODO I must be missing something - why aren't we just looking at */
394 /* the event.key.keysym.unicode value instead of going through this */
395 /* giant switch statement? */
396
397 switch(event.key.keysym.sym)
398 {
399 case SDLK_ESCAPE:
400 if (Pause() == 1)
401 quit = 1;
402 // continue loop and/or redraw screen
403 state = 1;
404 break;
405
406 case SDLK_F10:
407 SwitchScreenMode();
408 recalc_positions();
409 create_labels();
410 state = 1;
411 break;
412
413 case SDLK_DOWN: //practice next phase in list
414 if (cur_phrase < num_phrases - 1)
415 {
416 cur_phrase++;
417 state = 0;
418 }
419 break;
420
421 case SDLK_UP: //practice previous phase in list
422 if (cur_phrase > 0)
423 {
424 cur_phrase--;
425 state = 0;
426 }
427 break;
428
429 case SDLK_BACKQUOTE:
430 if(shift_pressed)
431 tmp='~';
432 else
433 tmp='`';
434 break;
435
436 case SDLK_COMMA:
437 if(shift_pressed)
438 tmp='<';
439 else
440 tmp=',';
441 break;
442
443 case SDLK_MINUS:
444 if(shift_pressed)
445 tmp='_';
446 else
447 tmp='-';
448 break;
449
450 case SDLK_PERIOD:
451 if(shift_pressed)
452 tmp='>';
453 else
454 tmp='.';
455 break;
456
457 case SDLK_SLASH:
458 if(shift_pressed)
459 tmp='?';
460 else
461 tmp='/';
462 break;
463
464 case SDLK_0:
465 if(shift_pressed)
466 tmp=')';
467 else
468 tmp='0';
469 break;
470
471 case SDLK_1:
472 if(shift_pressed)
473 tmp='!';
474 else
475 tmp='1';
476 break;
477
478 case SDLK_2:
479 if(shift_pressed)
480 tmp='@';
481 else
482 tmp='2';
483 break;
484
485 case SDLK_3:
486 if(shift_pressed)
487 tmp='#';
488 else
489 tmp='3';
490 break;
491
492 case SDLK_4:
493 if(shift_pressed)
494 tmp='$';
495 else
496 tmp='4';
497 break;
498
499 case SDLK_5:
500 if(shift_pressed)
501 tmp='%';
502 else
503 tmp='5';
504 break;
505
506 case SDLK_6:
507 if(shift_pressed)
508 tmp='^';
509 else
510 tmp='6';
511 break;
512
513 case SDLK_7:
514 if(shift_pressed)
515 tmp='&';
516 else
517 tmp='7';
518 break;
519
520 case SDLK_8:
521 if(shift_pressed)
522 tmp='*';
523 else
524 tmp='8';
525 break;
526
527 case SDLK_9:
528 if(shift_pressed)
529 tmp='(';
530 else
531 tmp='9';
532 break;
533
534 case SDLK_SEMICOLON:
535 if(shift_pressed)
536 tmp=':';
537 else
538 tmp=';';
539 break;
540
541 case SDLK_EQUALS:
542 if(shift_pressed)
543 tmp='+';
544 else
545 tmp='=';
546 break;
547
548 case SDLK_LEFTBRACKET:
549 if(shift_pressed)
550 tmp='{';
551 else
552 tmp='[';
553 break;
554
555 case SDLK_BACKSLASH:
556 if(shift_pressed)
557 tmp='|';
558 else
559 tmp='\\';
560 break;
561
562 case SDLK_RIGHTBRACKET:
563 if(shift_pressed)
564 tmp='}';
565 else
566 tmp=']';
567 break;
568
569 case SDLK_QUOTE:
570 if(shift_pressed)
571 tmp='"';
572 else
573 tmp='\'';
574 break;
575
576 case SDLK_SPACE: tmp=' '; break;
577 case SDLK_a: tmp='a'; break;
578 case SDLK_b: tmp='b'; break;
579 case SDLK_c: tmp='c'; break;
580 case SDLK_d: tmp='d'; break;
581 case SDLK_e: tmp='e'; break;
582 case SDLK_f: tmp='f'; break;
583 case SDLK_g: tmp='g'; break;
584 case SDLK_h: tmp='h'; break;
585 case SDLK_i: tmp='i'; break;
586 case SDLK_j: tmp='j'; break;
587 case SDLK_k: tmp='k'; break;
588 case SDLK_l: tmp='l'; break;
589 case SDLK_m: tmp='m'; break;
590 case SDLK_n: tmp='n'; break;
591 case SDLK_o: tmp='o'; break;
592 case SDLK_p: tmp='p'; break;
593 case SDLK_q: tmp='q'; break;
594 case SDLK_r: tmp='r'; break;
595 case SDLK_s: tmp='s'; break;
596 case SDLK_t: tmp='t'; break;
597 case SDLK_u: tmp='u'; break;
598 case SDLK_v: tmp='v'; break;
599 case SDLK_w: tmp='w'; break;
600 case SDLK_x: tmp='x'; break;
601 case SDLK_y: tmp='y'; break;
602 case SDLK_z: tmp='z'; break;
603 /* ignore other keys: */
604 default: break;
605 }
606
607 /* If state has changed as direct result of keypress (e.g. F10), leave */
608 /* poll event loop so we don't treat it as a simple 'wrong' key: */
609 if (state == 0
610 || state == 1)
611 continue;
612
613 /* Change to uppercase if shift used */
614 if(shift_pressed)
615 tmp=toupper(tmp);
616
617 if ( key != -1 )
618 updatekeylist(key,tmp);
619
620 /* Record elapsed time for this keypress and update running total: */
621 a = SDL_GetTicks();
622 keytimes[cursor] = a - start;
623 start = a;
624
625 total += keytimes[cursor];
626 sprintf(time_str, "%.2f %s", (float) total / 1000, N_("sec"));
627 sprintf(chars_typed_str, "%d", correct_chars);
628 sprintf(cpm_str, "%.1f", (float) correct_chars /((float)total/60000));
629 sprintf(wpm_str, "%.1f", (float) ((float) correct_chars/5) /((float) total/60000));
630 sprintf(errors_str, "%d", wrong_chars);
631
632 /* Calculate accuracy, avoiding divide-by-zero error: */
633 if (correct_chars + wrong_chars == 0)
634 accuracy = 1;
635 else
636 accuracy = (float)correct_chars/((float) (correct_chars + wrong_chars));
637 sprintf(accuracy_str, "%.1f%%", accuracy * 100);
638
639
640 /****************************************************/
641 /* ---------- If user typed correct character, handle it: --------------- */
642 if (phrases[cur_phrase][cursor] == event.key.keysym.unicode)
643 {
644 cursor++;
645 correct_chars++;
646
647 /* Handle wrapping if we are at the end of the current display. */
648 /* NOTE now also checking for space at end of line so we wrap */
649 /* automatically without waiting for user to type invisible */
650 /* space */
651 if (cursor >= prev_wrap + wrap_pt + 2) /* wrap onto next line */
652 {
653 /* This will cause the next line of the phrase to be drawn: */
654 prev_wrap = prev_wrap + wrap_pt + 2;
655 state = 1;
656 }
657 else if ((cursor == prev_wrap + wrap_pt + 1) /* skip terminal space */
658 && (phrases[cur_phrase][cursor] == ' '))
659 {
660 /* Need to increment cursor another time in this case: */
661 cursor ++;
662 prev_wrap = prev_wrap + wrap_pt + 2;
663 state = 1;
664 }
665 else
666 state = 2;
667
668 /* Redraw everything below any "completed" lines of input text, */
669 /* except we don't want to redraw keyboard to avoid flicker: */
670 tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
671 medfontsize, &white,
672 cursor - prev_wrap);
673
674 if (tmpsurf)
675 {
676 SDL_BlitSurface(CurrentBkgd(), &user_text_rect, screen, &user_text_rect);
677 SDL_BlitSurface(tmpsurf, NULL, screen, &user_text_rect);
678 SDL_FreeSurface(tmpsurf);
679 tmpsurf = NULL;
680 }
681
682
683 tmpsurf = BlackOutline(time_str, fontsize, &white);
684 if (tmpsurf)
685 {
686 SDL_BlitSurface(CurrentBkgd(), &time_rect, screen, &time_rect);
687 SDL_BlitSurface(tmpsurf, NULL, screen, &time_rect);
688 SDL_FreeSurface(tmpsurf);
689 tmpsurf = NULL;
690 }
691
692 tmpsurf = BlackOutline(chars_typed_str, fontsize, &white);
693 if (tmpsurf)
694 {
695 SDL_BlitSurface(CurrentBkgd(), &chars_typed_rect, screen, &chars_typed_rect);
696 SDL_BlitSurface(tmpsurf, NULL, screen, &chars_typed_rect);
697 SDL_FreeSurface(tmpsurf);
698 tmpsurf = NULL;
699 }
700
701 tmpsurf = BlackOutline(cpm_str, fontsize, &white);
702 if (tmpsurf)
703 {
704 SDL_BlitSurface(CurrentBkgd(), &cpm_rect, screen, &cpm_rect);
705 SDL_BlitSurface(tmpsurf, NULL, screen, &cpm_rect);
706 SDL_FreeSurface(tmpsurf);
707 tmpsurf = NULL;
708 }
709
710 tmpsurf = BlackOutline(wpm_str, fontsize, &white);
711 if (tmpsurf)
712 {
713 SDL_BlitSurface(CurrentBkgd(), &wpm_rect, screen, &wpm_rect);
714 SDL_BlitSurface(tmpsurf, NULL, screen, &wpm_rect);
715 SDL_FreeSurface(tmpsurf);
716 tmpsurf = NULL;
717 }
718
719 tmpsurf = BlackOutline(errors_str, fontsize, &white);
720 if (tmpsurf)
721 {
722 SDL_BlitSurface(CurrentBkgd(), &errors_rect, screen, &errors_rect);
723 SDL_BlitSurface(tmpsurf, NULL, screen, &errors_rect);
724 SDL_FreeSurface(tmpsurf);
725 tmpsurf = NULL;
726 }
727
728 tmpsurf = BlackOutline(accuracy_str, fontsize, &white);
729 if (tmpsurf)
730 {
731 SDL_BlitSurface(CurrentBkgd(), &accuracy_rect, screen, &accuracy_rect);
732 SDL_BlitSurface(tmpsurf, NULL, screen, &accuracy_rect);
733 SDL_FreeSurface(tmpsurf);
734 tmpsurf = NULL;
735 }
736
737 SDL_Flip(screen);
738
739 /* If player has completed phrase, celebrate! */
740 if (cursor == wcslen(phrases[cur_phrase]))
741 {
742 /* Draw Tux celebrating: */
743 {
744 int done = 0;
745
746 PlaySound(cheer);
747
748 while (!done)
749 {
750 while (SDL_PollEvent(&event))
751 {
752 if ((event.type == SDL_KEYDOWN)
753 ||(event.type == SDL_MOUSEBUTTONDOWN))
754 done = 1;
755 }
756
757 /* Draw Tux: */
758 SDL_BlitSurface(CurrentBkgd(), &tux_loc, screen, &tux_loc);
759 if (tux_win && tux_win->frame[tux_win->cur])
760 SDL_BlitSurface(tux_win->frame[tux_win->cur], NULL, screen, &tux_loc);
761 SDL_UpdateRect(screen, tux_loc.x, tux_loc.y, tux_loc.w, tux_loc.h);
762 NEXT_FRAME(tux_win);
763 SDL_Delay(200);
764 }
765 }
766
767 /* if we are just doing a single phrase passed as arg to function, */
768 /* we stop here: */
769 if (once_only)
770 quit = 1;
771 else /* means we are using the phrases from the file */
772 {
773 /* Go on to next phrase, or back to first one if all done */
774 if (cur_phrase < num_phrases)
775 cur_phrase++;
776 else
777 cur_phrase = 0;
778 }
779 state = 0;
780 }
781 }
782 else /* -------- handle incorrect key press: -------------*/
783 {
784 // int key = GetIndex((wchar_t)event.key.keysym.unicode);
785 if ( key != -1 )
786 {
787 keypress1= GetWrongKeypress(key);
788
789 if (keypress1) // avoid segfault if NULL
790 {
791 SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
792 SDL_FreeSurface(keypress1);
793 }
794 }
795 state = 2;
796
797 /* Don't count shift keys as wrong: */
798 if (event.key.keysym.sym != SDLK_RSHIFT
799 && event.key.keysym.sym != SDLK_LSHIFT)
800 {
801 /* Also, don't count spacebar as wrong on first char */
802 /* after wrap because we automatically skip it above */
803 if((cursor != prev_wrap)
804 ||(event.key.keysym.sym != SDLK_SPACE))
805 {
806 wrong_chars++;
807 PlaySound(wrong);
808 }
809 }
810 }
811
812 } /* End of "if(event.type == SDL_KEYDOWN)" block --*/
813
814 } /* ----- End of SDL_PollEvent() loop -------------- */
815
816 /* Draw next tux frame if appropriate: */
817 if ((SDL_GetTicks() - tuxtime) > SPRITE_FRAME_TIME)
818 {
819 tuxtime = SDL_GetTicks();
820
821 SDL_BlitSurface(CurrentBkgd(), &tux_loc, screen, &tux_loc);
822
823 if (tux_stand && tux_stand->frame[tux_stand->cur])
824 SDL_BlitSurface(tux_stand->frame[tux_stand->cur], NULL, screen, &tux_loc);
825 NEXT_FRAME(tux_stand);
826 }
827
828 SDL_UpdateRect(screen, 0, 0, 0, 0);
829 // SDL_Flip(screen);
830 SDL_Delay(30); /* FIXME should keep frame rate constant */
831
832 }while (!quit); /* ------- End of main event loop ------------- */
833
834 savekeyboard();
835
836 practice_unload_media();
837
838 return quit;
839 }
840
841
842
843 /************************************************************************/
844 /* */
845 /* "Private" functions (local to practice.c) */
846 /* */
847 /************************************************************************/
848
849 /* Select appropriate font sizes based on the screen we're working with: */
calc_font_sizes(void)850 static void calc_font_sizes(void)
851 {
852 fontsize = (screen->h)/28;
853 medfontsize = fontsize * 1.5;
854 bigfontsize = fontsize * 4;
855 }
856
practice_load_media(void)857 static int practice_load_media(void)
858 {
859 int i;
860 char fn[FNLEN];
861 int load_failed = 0;
862 int labels_ok = 0;
863
864 DEBUGCODE { printf("Entering practice_load_media\n"); }
865
866
867 /* load needed SDL_Surfaces: */
868 LoadBothBkgds("main_bkg.png");
869 hands = LoadImage("hands/hands.png", IMG_ALPHA);
870 hand_shift[0] = LoadImage("hands/none.png", IMG_ALPHA);
871 hand_shift[1] = LoadImage("hands/lshift.png", IMG_ALPHA);
872 hand_shift[2] = LoadImage("hands/rshift.png", IMG_ALPHA);
873 keyboard = LoadImage("keyboard/keyboard.png", IMG_ALPHA);
874
875 for (i = 0; i < 10; i++)
876 {
877 sprintf(fn, "hands/%d.png", i);
878 hand[i] = LoadImage(fn, IMG_ALPHA);
879 if (!hand[i])
880 load_failed = 1;
881 }
882
883 /* load tux sprites: */
884 tux_win = LoadSprite("tux/win", IMG_ALPHA);
885 tux_stand = LoadSprite("tux/stand", IMG_ALPHA);
886 /* load needed sounds: */
887 wrong = LoadSound("buzz.wav");
888 cheer = LoadSound("cheer.wav");
889
890 /* load needed fonts: */
891 calc_font_sizes();
892
893 /* create labels: */
894 labels_ok = create_labels();
895
896 /* Get out if anything failed to load (except sounds): */
897 if (load_failed
898 ||!hands
899 ||!CurrentBkgd()
900 ||!tux_win
901 ||!tux_stand
902 ||!keyboard
903 ||!hand_shift[0]
904 ||!hand_shift[1]
905 ||!hand_shift[2]
906 ||!labels_ok)
907 {
908 fprintf(stderr, "practice_load_media() - failed to load needed media \n");
909 print_load_results();
910 return 0;
911 }
912
913 /* Now render letters for glyphs in alphabet: */
914 /* This is used for keyboard graphic */
915 RenderLetters(fontsize);
916 GenerateKeyboard(keyboard);
917
918 LOG("DONE - Loading practice media\n");
919 DEBUGCODE { printf("Leaving practice_load_media\n"); }
920 return 1;
921 }
922
923
924
print_load_results(void)925 static void print_load_results(void)
926 {
927 LOG("\npractice - print_load_results:\n");
928 /* Get out if anything failed to load: */
929 if (!CurrentBkgd())
930 { LOG("CurrentBkgd() did not load\n");}
931 if (!hands)
932 { LOG("hands did not load\n");}
933 if (!tux_win)
934 { LOG("tux_win did not load\n");}
935 if (!tux_stand)
936 { LOG("tux_stand did not load\n");}
937 if (!keyboard)
938 { LOG("keyboard did not load\n");}
939 if (!hand_shift[0])
940 { LOG("hand_shift[0] did not load\n");}
941 if (!hand_shift[1])
942 { LOG("hand_shift[1] did not load\n");}
943 if (!hand_shift[2])
944 { LOG("hand_shift[2] did not load\n");}
945 if (!time_label_srfc)
946 { LOG("time_label_srfc did not load\n");}
947 if (!chars_label_srfc)
948 { LOG("chars_label_srfc did not load\n");}
949 if (!cpm_label_srfc)
950 { LOG("cpm_label_srfc did not load\n");}
951 if (!wpm_label_srfc)
952 { LOG("wpm_label_srfc did not load\n");}
953 if (!time_label_srfc)
954 { LOG("time_label_srfc did not load\n");}
955 if (!errors_label_srfc)
956 { LOG("errors_label_srfc did not load\n");}
957 if (!accuracy_label_srfc)
958 { LOG("accuracy_label_srfc did not load\n");}
959
960 LOG("End print_load_results()\n\n");
961 }
962
recalc_positions(void)963 static void recalc_positions(void)
964 {
965 int text_height;
966 calc_font_sizes();
967 text_height = fontsize * 1.5;
968
969 DEBUGCODE
970 {
971 fprintf(stderr, "Entering recalc_positions(), screen is %d x %d\n", screen->w, screen->h);
972 }
973
974 if (!keyboard
975 ||!tux_win
976 ||!tux_win->frame[0]
977 ||!hand[0])
978 {
979 fprintf(stderr, "recalc_positions() - needed ptr invalid - returning\n");
980 }
981
982 /* Screen is divided into three areas or 'panes' : */
983 /*
984 *************************************
985 * * *
986 * left * top *
987 * * *
988 * ****************************
989 * * *
990 * * *
991 * * bottom *
992 * * *
993 * * *
994 *************************************
995 */
996
997 left_pane.x = 0;
998 left_pane.y = 0;
999 left_pane.w = screen->w * 0.25;
1000 left_pane.h = screen->h;
1001
1002 top_pane.x = screen->w * 0.25;
1003 top_pane.y = 0;
1004 top_pane.w = screen->w * 0.75;
1005 top_pane.h = screen->h * 0.4;
1006
1007 bottom_pane.x = screen->w * 0.25;
1008 bottom_pane.y = screen->h * 0.4;
1009 bottom_pane.w = screen->w * 0.75;
1010 bottom_pane.h = screen->h * 0.6;
1011
1012 /* Set up all the locations within the left pane: */
1013 tux_loc.x = left_pane.x + 5;
1014 tux_loc.y = left_pane.y + 5;
1015 tux_loc.w = tux_stand->frame[0]->w;
1016 tux_loc.h = tux_stand->frame[0]->h;
1017
1018 time_label.x = left_pane.x + 5;
1019 time_label.y = tux_loc.y + tux_loc.h;
1020 time_label.w = left_pane.w - 5;
1021 time_label.h = text_height;
1022
1023 time_rect.x = left_pane.x + 5;
1024 time_rect.y = time_label.y + time_label.h;
1025 time_rect.w = left_pane.w - 5;
1026 time_rect.h = text_height;
1027
1028 chars_typed_label.x = left_pane.x + 5;
1029 chars_typed_label.y = time_rect.y + time_rect.h;
1030 chars_typed_label.w = left_pane.w - 5;
1031 chars_typed_label.h = text_height;
1032
1033 chars_typed_rect.x = left_pane.x + 5;
1034 chars_typed_rect.y = chars_typed_label.y + chars_typed_label.h;
1035 chars_typed_rect.w = left_pane.w - 5;
1036 chars_typed_rect.h = text_height;
1037
1038 cpm_label.x = left_pane.x + 5;
1039 cpm_label.y = chars_typed_rect.y + chars_typed_rect.h;
1040 cpm_label.w = left_pane.w - 5;
1041 cpm_label.h = text_height;
1042
1043 cpm_rect.x = left_pane.x + 5;
1044 cpm_rect.y = cpm_label.y + cpm_label.h;
1045 cpm_rect.w = left_pane.w - 5;
1046 cpm_rect.h = text_height;
1047
1048 wpm_label.x = left_pane.x + 5;
1049 wpm_label.y = cpm_rect.y + cpm_rect.h;
1050 wpm_label.w = left_pane.w - 5;
1051 wpm_label.h = text_height;
1052
1053 wpm_rect.x = left_pane.x + 5;
1054 wpm_rect.y = wpm_label.y + wpm_label.h;
1055 wpm_rect.w = left_pane.w - 5;
1056 wpm_rect.h = text_height;
1057
1058 errors_label.x = left_pane.x + 5;
1059 errors_label.y = wpm_rect.y + wpm_rect.h;
1060 errors_label.w = left_pane.w - 5;
1061 errors_label.h = text_height;
1062
1063 errors_rect.x = left_pane.x + 5;
1064 errors_rect.y = errors_label.y + errors_label.h;
1065 errors_rect.w = left_pane.w - 5;
1066 errors_rect.h = text_height;
1067
1068 accuracy_label.x = left_pane.x + 5;
1069 accuracy_label.y = errors_rect.y + errors_rect.h;
1070 accuracy_label.w = left_pane.w - 5;
1071 accuracy_label.h = text_height;
1072
1073 accuracy_rect.x = left_pane.x + 5;
1074 accuracy_rect.y = accuracy_label.y + accuracy_label.h;
1075 accuracy_rect.w = left_pane.w - 5;
1076 accuracy_rect.h = text_height;
1077
1078 /* Set up all the locations within the top pane: */
1079 phr_text_rect.x = top_pane.x + 5;
1080 phr_text_rect.y = top_pane.y + top_pane.h * 0.3;
1081 phr_text_rect.w = top_pane.w - 5;
1082 phr_text_rect.h = medfontsize;
1083
1084 /* we can't just use phr_text_rect.w to calc wrap */
1085 /* because SDL_BlitSurface() clobbers it: */
1086 phrase_draw_width = phr_text_rect.w;
1087
1088 user_text_rect.x = top_pane.x + 5;
1089 user_text_rect.y = top_pane.y + top_pane.h * 0.6;
1090 user_text_rect.w = top_pane.w - 5;
1091 user_text_rect.h = medfontsize * 1.5;
1092
1093 /* Set up all the locations within the bottom pane: */
1094 keyboard_loc.x = bottom_pane.x + bottom_pane.w/4 - keyboard->w/4;
1095 keyboard_loc.y = bottom_pane.y + 5;
1096 keyboard_loc.w = keyboard->w;
1097 keyboard_loc.h = keyboard->h;
1098
1099 hand_loc.x = keyboard_loc.x;
1100 hand_loc.y = keyboard_loc.y + keyboard_loc.h + 20;
1101 hand_loc.w = (hand[0]->w);
1102 hand_loc.h = (hand[0]->h);
1103
1104
1105 nextletter_rect.x = keyboard_loc.x + keyboard_loc.w - 80;
1106 nextletter_rect.y = keyboard_loc.y + keyboard_loc.h;
1107 nextletter_rect.w = bigfontsize * 1.5;
1108 nextletter_rect.h = bigfontsize * 1.5;
1109
1110 }
1111
1112
practice_unload_media(void)1113 static void practice_unload_media(void)
1114 {
1115 int i;
1116
1117 FreeBothBkgds();
1118 FreeLetters();
1119
1120 if (time_label_srfc)
1121 SDL_FreeSurface(time_label_srfc);
1122 time_label_srfc = NULL;
1123
1124 if (chars_label_srfc)
1125 SDL_FreeSurface(chars_label_srfc);
1126 chars_label_srfc = NULL;
1127
1128 if (cpm_label_srfc)
1129 SDL_FreeSurface(cpm_label_srfc);
1130 cpm_label_srfc = NULL;
1131
1132 if (wpm_label_srfc)
1133 SDL_FreeSurface(wpm_label_srfc);
1134 wpm_label_srfc = NULL;
1135
1136 if (errors_label_srfc)
1137 SDL_FreeSurface(errors_label_srfc);
1138 errors_label_srfc = NULL;
1139
1140 if (accuracy_label_srfc)
1141 SDL_FreeSurface(accuracy_label_srfc);
1142 accuracy_label_srfc = NULL;
1143
1144 if (hands)
1145 SDL_FreeSurface(hands);
1146 hands = NULL;
1147
1148 for(i = 0; i < 3; i++)
1149 {
1150 if (hand_shift[i])
1151 SDL_FreeSurface(hand_shift[i]);
1152 hand_shift[i] = NULL;
1153 }
1154
1155 if (keyboard)
1156 SDL_FreeSurface(keyboard);
1157 keyboard = NULL;
1158
1159 for (i = 0; i < 10; i++)
1160 {
1161 if (hand[i])
1162 SDL_FreeSurface(hand[i]);
1163 hand[i] = NULL;
1164 }
1165
1166 if (tux_stand)
1167 {
1168 FreeSprite(tux_stand);
1169 tux_stand = NULL;
1170 }
1171
1172 if (tux_win)
1173 {
1174 FreeSprite(tux_win);
1175 tux_win = NULL;
1176 }
1177
1178 if (cheer)
1179 Mix_FreeChunk(cheer);
1180 cheer = NULL;
1181
1182 if (wrong)
1183 Mix_FreeChunk(wrong);
1184 wrong = NULL;
1185 }
1186
1187
1188 // /* looks like dead code: */
1189 // static void show(char t)
1190 // {
1191 // SDL_Rect dst;
1192 // SDL_Surface* s = NULL;
1193 //
1194 // s = GetWhiteGlyph((int)t);
1195 // if (!s)
1196 // return;
1197 //
1198 // dst.x = 320 - (s->w/2);
1199 // dst.y = 100;
1200 // dst.w = s->w;
1201 // dst.h = s->h;
1202 // SDL_BlitSurface(s, NULL, screen, &dst);
1203 // }
1204
1205
1206 /* Looks for phrases.txt in theme, then in default if not found, */
1207 /* loads it into phrases[][] array. Returns number of phrases */
1208 /* successfully loaded. */
load_phrases(const char * phrase_file)1209 static int load_phrases(const char* phrase_file)
1210 {
1211 int found = 0;
1212 int num_phrases = 0;
1213 char buf[MAX_PHRASE_LENGTH];
1214 FILE* fp;
1215 char fn[FNLEN];
1216
1217 /* If using theme, look there first: */
1218 if (!settings.use_english)
1219 {
1220 sprintf(fn , "%s/%s", settings.theme_data_path, phrase_file);
1221 if (CheckFile(fn))
1222 found = 1;
1223 }
1224
1225 /* Now checking English: */
1226 if (!found)
1227 {
1228 sprintf(fn , "%s/%s", settings.default_data_path, phrase_file);
1229 if (CheckFile(fn))
1230 found = 1;
1231 }
1232
1233 if (!found)
1234 {
1235 fprintf(stderr, "Could not find phrases file '%s' - cannot do Practice\n",
1236 phrase_file);
1237 return 0;
1238 }
1239
1240 DEBUGCODE { printf("load_phrases(): phrases file is '%s'\n", fn ); }
1241
1242 /* We know it will open OK because we already ran CheckFile() on it */
1243 fp = fopen(fn, "r");
1244
1245 /* So now copy each line into phrases array: */
1246 /* NOTE we need to convert to wchar_t so just fscanf won't work! */
1247 while (!feof(fp) && num_phrases <= MAX_PHRASES)
1248 {
1249 /* Similar check to above but compiler complains unless we */
1250 /* inspect return value of fscanf(): */
1251 if (EOF != fscanf(fp, "%[^\n]\n", buf))
1252 {
1253 ConvertFromUTF8(phrases[num_phrases], buf, MAX_PHRASE_LENGTH);
1254 DEBUGCODE {printf("phrase %d:\t%S\n", num_phrases, phrases[num_phrases]);}
1255 num_phrases++;
1256 }
1257 }
1258
1259 if (num_phrases > MAX_PHRASES)
1260 {
1261 fprintf(stderr, "File contains more than MAX_PHRASES - stopping\n");
1262 num_phrases = MAX_PHRASES;
1263 }
1264
1265 fclose(fp);
1266
1267 DOUT(num_phrases);
1268
1269 return num_phrases;
1270 }
1271
1272
1273
1274 /* Returns index relative to wstr of last char to be printed before break. */
1275 /* (i.e. end of last full word that fits within 'width' */
find_next_wrap(const wchar_t * wstr,int font_size,int width)1276 static int find_next_wrap(const wchar_t* wstr, int font_size, int width)
1277 {
1278 wchar_t buf[MAX_PHRASE_LENGTH];
1279 char UTF8buf[MAX_PHRASE_LENGTH];
1280 SDL_Surface* s = NULL;
1281 int word_end = -1;
1282 int prev_word_end = -1;
1283
1284 int i = 0;
1285 int phr_length = 0;
1286 int test_w = 0; /* The width in pixels of the SDL-rendered string */
1287 /* FIXME get rid of this once overhaul done: */
1288
1289 LOG("Entering find__next_wrap\n");
1290
1291 /* Make sure args OK: */
1292 if (!wstr)
1293 {
1294 fprintf(stderr, "find_next_wrap() - error - invalid string argument\n");
1295 return -1;
1296 }
1297
1298 DOUT(width);
1299 DEBUGCODE{ fprintf(stderr, "wstr = %S\n", wstr);}
1300
1301 phr_length = wcslen(wstr);
1302
1303 DOUT(phr_length);
1304 /* Using 'MAX_PHRASE_LENGTH - 1' will make sure our copied string is */
1305 /* null-terminated, even if it didn't fit. */
1306
1307 if (phr_length > (MAX_PHRASE_LENGTH - 1))
1308 {
1309 fprintf(stderr, "find_next_wrap() - error - phrase exceeds MAX_PHRASE_LENGTH\n");
1310 return -1;
1311 }
1312
1313 /* The function will eventually return from within the loop */
1314 while(1)
1315 {
1316 /* Find next either next space or end of string to check width */
1317 for( ;
1318 i < phr_length && wstr[i] != ' ';
1319 i++);
1320
1321 DOUT(i);
1322
1323 /* If exited because space found, back up one so we are at last char in word: */
1324 if (wstr[i] == ' ')
1325 word_end = i - 1;
1326 else
1327 word_end = i;
1328
1329 /* See if we have exceeded the width */
1330 /* Copy string into buf and null terminate after point to be checked: */
1331 wcsncpy(buf, wstr, MAX_PHRASE_LENGTH);
1332 buf[word_end + 1] = '\0';
1333 DEBUGCODE{ fprintf(stderr, "buf = %S\n", buf);}
1334
1335 /* Need to convert to UTF8 because couldn't get UNICODE version to work: */
1336 ConvertToUTF8(buf, UTF8buf, MAX_PHRASE_LENGTH);
1337 /* Now check width of string: */
1338 s = SimpleText(UTF8buf, font_size, &white);
1339 if (!s)
1340 {
1341 /* An error occurred: */
1342 return -1;
1343 }
1344
1345 test_w = s->w;
1346 SDL_FreeSurface(s);
1347 s = NULL;
1348
1349 DOUT(test_w);
1350 DOUT(width);
1351 /* If we've gone past the width, the previous space was the wrap point, */
1352 /* whether or not we are at the end of the string: */
1353 if (test_w > width)
1354 {
1355 DEBUGCODE
1356 {
1357 fprintf(stderr, "width exceeded, returning end of previous word as wrap point\n");
1358 fprintf(stderr, "prev_word_end is %d\n", prev_word_end);
1359 fprintf(stderr, "leaving find_next_wrap()\n");
1360 }
1361 return prev_word_end;
1362 }
1363 else
1364 {
1365 if (i >= phr_length)
1366 {
1367 DEBUGCODE
1368 {
1369 fprintf(stderr, "width not exceeded, returning because end of string reached\n");
1370 fprintf(stderr, "word_end is %d\n", word_end);
1371 }
1372 /* We reached the end of the phrase without exceeding the width, */
1373 /* so just return our current position: */
1374 return word_end;
1375 }
1376 else
1377 {
1378 prev_word_end = word_end;
1379 i++;
1380 }
1381 }
1382 }
1383 }
1384
1385
1386 /* FIXME this isn't very safe because index could be out of allocated string, */
1387 /* and there a very good way to test for this within this function. */
1388 /* Displays the next letter to be typed in a large font */
display_next_letter(const wchar_t * str,Uint16 index)1389 static void display_next_letter(const wchar_t *str, Uint16 index)
1390 {
1391 wchar_t ltr[2];
1392 SDL_Surface* s = NULL;
1393
1394 if (!str || (index >= MAX_PHRASE_LENGTH))
1395 return;
1396
1397 ltr[0] = str[index];
1398 ltr[1] = '\0';
1399
1400 s = BlackOutline_w(ltr, bigfontsize, &white, 1);
1401
1402 if (s)
1403 {
1404 SDL_BlitSurface(CurrentBkgd(), &nextletter_rect, screen, &nextletter_rect);
1405 SDL_BlitSurface(s, NULL, screen, &nextletter_rect);
1406 SDL_FreeSurface(s);
1407 s = NULL;
1408 }
1409 }
1410
1411
GetKeypress1(int index)1412 SDL_Surface* GetKeypress1(int index)
1413 {
1414 char buf[50];
1415 GetKeyPos(index,buf);
1416 return (LoadImage(buf, IMG_ALPHA));
1417 }
1418
1419
GetWrongKeypress(int index)1420 SDL_Surface* GetWrongKeypress(int index)
1421 {
1422 char buf[50];
1423 GetWrongKeyPos(index,buf);
1424 return (LoadImage(buf, IMG_ALPHA));
1425 }
1426
1427
GetKeypress2(int index)1428 SDL_Surface* GetKeypress2(int index)
1429 {
1430
1431 char buf[50];
1432 GetKeyShift(index, buf);
1433 return (LoadImage(buf, IMG_ALPHA));
1434 }
1435
create_labels(void)1436 static int create_labels(void)
1437 {
1438 if (time_label_srfc)
1439 SDL_FreeSurface(time_label_srfc);
1440 time_label_srfc = BlackOutline(_("Time"), fontsize, &yellow);
1441
1442 if (chars_label_srfc)
1443 SDL_FreeSurface(chars_label_srfc);
1444 chars_label_srfc = BlackOutline(_("Chars"), fontsize, &yellow);
1445
1446 if (cpm_label_srfc)
1447 SDL_FreeSurface(cpm_label_srfc);
1448 cpm_label_srfc = BlackOutline(_("CPM"), fontsize, &yellow);
1449
1450 if (wpm_label_srfc)
1451 SDL_FreeSurface(wpm_label_srfc);
1452 wpm_label_srfc = BlackOutline(_("WPM"), fontsize, &yellow);
1453
1454 if (errors_label_srfc)
1455 SDL_FreeSurface(errors_label_srfc);
1456 errors_label_srfc = BlackOutline(_("Errors"), fontsize, &yellow);
1457
1458 if (accuracy_label_srfc)
1459 SDL_FreeSurface(accuracy_label_srfc);
1460 accuracy_label_srfc = BlackOutline(_("Accuracy"), fontsize, &yellow);
1461
1462 if (time_label_srfc
1463 && chars_label_srfc
1464 && cpm_label_srfc
1465 && wpm_label_srfc
1466 && errors_label_srfc
1467 && accuracy_label_srfc)
1468 return 1;
1469 else
1470 return 0;
1471 }
1472