word_t *remove_word(word_t *words, const char *word_name) { word_t *head = words; words = get(words, word_name); if(words == NULL) return head; if(is_word_equal(words, words->next)) { free_word(words); return NULL; } else { words->next->previous = words->previous; words->previous->next = words->next; word_t *ans = words->next; free_word(words); return ans; } }
/* Divide each of the words in the sentence into one character words, without changing the positions of those characters. */ static void split_words (state *s, sentence *se) { word **words2; int nwords2 = 0; int i, j; for (i = 0; i < se->nwords; i++) nwords2 += strlen (se->words[i]->text); words2 = (word **) calloc (nwords2, sizeof(*words2)); for (i = 0, j = 0; i < se->nwords; i++) { word *ow = se->words[i]; int L = strlen (ow->text); int k; int x = ow->x; int y = ow->y; int sx = ow->start_x; int sy = ow->start_y; int tx = ow->target_x; int ty = ow->target_y; for (k = 0; k < L; k++) { char *t2 = malloc (2); word *w2; int xoff, yoff; t2[0] = ow->text[k]; t2[1] = 0; w2 = new_word (s, se, t2, True); words2[j++] = w2; xoff = (w2->lbearing - ow->lbearing); yoff = (ow->ascent - w2->ascent); w2->x = x + xoff; w2->y = y + yoff; w2->start_x = sx + xoff; w2->start_y = sy + yoff; w2->target_x = tx + xoff; w2->target_y = ty + yoff; x += w2->rbearing; sx += w2->rbearing; tx += w2->rbearing; } free_word (s, ow); se->words[i] = 0; } free (se->words); se->words = words2; se->nwords = nwords2; }
/* free the word, and put its text back at the front of the input queue, to be read next time. */ static void unread_word (state *s, word *w) { if (unread_word_text) abort(); unread_word_text = w->text; w->text = 0; free_word (s, w); }
void sound_game_reset(script_t* SCRIPT_ADDRESS, char* LANG_FILESET, char* MODE_FILESET, const char** SOUND_SOURCE_LIST, const char** SOUND_LIST) { set_mode_globals(SCRIPT_ADDRESS, LANG_FILESET, MODE_FILESET); sound_list = (char**) SOUND_LIST; sound_source_list = (char**) SOUND_SOURCE_LIST; next_state = STATE_MENU; submode = SUBMODE_NULL; incorrect_tries = 0; user_glyph = NULL; curr_glyph = NULL; user_word = free_word(user_word); curr_word = free_word(curr_word); cell = 0; cell_pattern = 0; cell_control = 0; scrolled = false; PRINTF("[MD3] Mode reset"); play_mp3(MODE_FILESET, "INT"); play_mp3(MODE_FILESET, "MSEL"); }
static void free_sentence (state *s, sentence *se) { int i; for (i = 0; i < se->nwords; i++) free_word (s, se->words[i]); if (se->words) free (se->words); if (se->fg.flags) XFreeColors (s->dpy, s->xgwa.colormap, &se->fg.pixel, 1, 0); if (se->bg.flags) XFreeColors (s->dpy, s->xgwa.colormap, &se->bg.pixel, 1, 0); if (se->font_name) free (se->font_name); if (se->font) XFreeFont (s->dpy, se->font); if (se->fg_gc) XFreeGC (s->dpy, se->fg_gc); free (se); }
/** * @brief Step through the main stages in the code. * @return Void */ void sound_game_main(script_t* SCRIPT_ADDRESS, char* LANG_FILESET, char* MODE_FILESET) { switch(next_state) { case STATE_MENU: if (io_user_abort == true) { PRINTF("[MD3] Quitting to main menu\n\r"); quit_mode(); io_init(); } cell = get_cell(); if (cell == NO_DOTS) { break; } cell_pattern = GET_CELL_PATTERN(cell); cell_control = GET_CELL_CONTROL(cell); switch (cell_control) { /*If user input is A, enter SUBMODE_PLAY; if input is B, enter SUBMODE_LEARN; else go back to menu*/ case WITH_ENTER: user_glyph = search_script(this_script, cell_pattern); if (cell_pattern == ENG_A) { play_glyph(user_glyph); submode = SUBMODE_PLAY; next_state = STATE_GENQUES; } else if (cell_pattern == ENG_B) { play_glyph(user_glyph); submode = SUBMODE_LEARN; next_state = STATE_GENQUES; } else { play_mp3(lang_fileset, MP3_INVALID_PATTERN); next_state = STATE_MENU; } break; case WITH_LEFT:case WITH_RIGHT:case WITH_CANCEL: break; } break; case STATE_GENQUES: length_entered_word = 0; current_word_index = 0; sound_source = sound_source_list[choose_sound_source()]; user_glyph = NULL; curr_glyph = NULL; user_word = free_word(user_word); curr_word = free_word(curr_word); next_state = STATE_PROMPT; break; case STATE_PROMPT: switch(submode) { case SUBMODE_PLAY: play_mp3(MODE_FILESET, "PLSA"); play_sound(MODE_FILESET, sound_source, false); break; case SUBMODE_LEARN: play_mp3(MODE_FILESET, "PLSB"); play_sound(MODE_FILESET, sound_source, true); break; default: break; } next_state = STATE_INPUT; break; case STATE_INPUT: if (io_user_abort == true) { PRINTF("[MD3] User aborted input\n\r"); next_state = STATE_REPROMPT; io_init(); } cell = get_cell(); if (cell == NO_DOTS) { break; } cell_pattern = GET_CELL_PATTERN(cell); cell_control = GET_CELL_CONTROL(cell); switch (cell_control) { case WITH_ENTER: user_glyph = search_script(this_script, cell_pattern); next_state = STATE_CHECK; PRINTF("[MD3] Checking answer\n\r"); break; case WITH_LEFT: next_state = STATE_PROMPT; break; case WITH_RIGHT: next_state = STATE_REPROMPT; break; case WITH_CANCEL: break; } break; case STATE_CHECK: curr_glyph = search_script(this_script, get_bits_from_letter(sound_source[length_entered_word])); if (glyph_equals(curr_glyph, user_glyph)) { play_glyph(curr_glyph); incorrect_tries = 0; length_entered_word++; user_word = add_glyph_to_word(user_word, user_glyph); if(length_entered_word != strlen(sound_source)) { play_mp3(lang_fileset, "GOOD"); next_state = STATE_INPUT; } else { play_mp3(lang_fileset, "GOOD"); play_mp3(lang_fileset, "NCWK"); switch (submode){ case SUBMODE_LEARN: play_sound(MODE_FILESET, sound_source, true); play_mp3(MODE_FILESET, "SAYS"); play_sound(MODE_FILESET, sound_source, false); break; case SUBMODE_PLAY: play_word(user_word); play_sound(MODE_FILESET, sound_source, true); } next_state = STATE_GENQUES; } } else { play_glyph(user_glyph); incorrect_tries++; PRINTF("[MD3] User answered incorrectly\n\r"); play_mp3(lang_fileset, "NO"); play_mp3(lang_fileset, MP3_TRY_AGAIN); play_word(user_word); if (incorrect_tries == MAX_INCORRECT_TRIES_1) { play_mp3(MODE_FILESET, "PLWR"); play_sound(MODE_FILESET, sound_source, true); curr_word = word_to_glyph_word(this_script, sound_source); play_word(curr_word); } else if (incorrect_tries >= 6) { play_glyph(curr_glyph); play_mp3(MODE_FILESET, "PRSS"); play_dot_sequence(curr_glyph); } next_state = STATE_INPUT; } break; case STATE_REPROMPT: switch(create_dialog("SKIP", ENTER_CANCEL | LEFT_RIGHT)) { case NO_DOTS: break; case CANCEL: PRINTF("[MD3] Reissuing prompt"); next_state = STATE_PROMPT; scrolled = false; break; case ENTER: PRINTF("[MD3] Skipping sound_source"); if (scrolled) next_state = STATE_PROMPT; else next_state = STATE_GENQUES; scrolled = false; break; case RIGHT: case LEFT: PRINTF("[MD3] Next sound_source"); length_entered_word = 0; current_word_index = 0; sound_source = sound_source_list[choose_sound_source()]; user_word = NULL; switch(submode) { case SUBMODE_PLAY: play_sound(MODE_FILESET, sound_source, false); break; case SUBMODE_LEARN: play_sound(MODE_FILESET, sound_source, true); break; default: break; } scrolled = true; break; default: break; } break; default: break; } }
/* Fill the sentence with new words: in "page" mode, fills the page with text; in "scroll" mode, just makes one long horizontal sentence. The sentence might have *no* words in it, if no text is currently available. */ static void populate_sentence (state *s, sentence *se) { int i = 0; int left, right, top, x, y; int space = 0; int line_start = 0; Bool done = False; int array_size = 100; se->move_chars_p = (s->mode == SCROLL ? False : (random() % 3) ? False : True); se->alignment = (random() % 3); recolor (s, se); if (se->words) { for (i = 0; i < se->nwords; i++) free_word (s, se->words[i]); free (se->words); } se->words = (word **) calloc (array_size, sizeof(*se->words)); se->nwords = 0; switch (s->mode) { case PAGE: left = random() % (s->xgwa.width / 3); right = s->xgwa.width - (random() % (s->xgwa.width / 3)); top = random() % (s->xgwa.height * 2 / 3); break; case SCROLL: left = 0; right = s->xgwa.width; top = random() % s->xgwa.height; break; default: abort(); break; } x = left; y = top; while (!done) { char *txt = get_word_text (s); word *w; if (!txt) { if (se->nwords == 0) return; /* If the stream is empty, bail. */ else break; /* If EOF after some words, end of sentence. */ } if (! se->font) /* Got a word: need a font now */ { pick_font (s, se); if (y < se->font->ascent) y += se->font->ascent; space = XTextWidth (se->font, " ", 1); } w = new_word (s, se, txt, !se->move_chars_p); /* If we have a few words, let punctuation terminate the sentence: stop gathering more words if the last word ends in a period, etc. */ if (se->nwords >= 4) { char c = w->text[strlen(w->text)-1]; if (c == '.' || c == '?' || c == '!') done = True; } /* If the sentence is kind of long already, terminate at commas, etc. */ if (se->nwords >= 12) { char c = w->text[strlen(w->text)-1]; if (c == ',' || c == ';' || c == ':' || c == '-' || c == ')' || c == ']' || c == '}') done = True; } if (se->nwords >= 25) /* ok that's just about enough out of you */ done = True; if (s->mode == PAGE && x + w->rbearing > right) /* wrap line */ { align_line (s, se, line_start, x, right); line_start = se->nwords; x = left; y += se->font->ascent; /* If we're close to the bottom of the screen, stop, and unread the current word. (But not if this is the first word, otherwise we might just get stuck on it.) */ if (se->nwords > 0 && y + se->font->ascent > s->xgwa.height) { unread_word (s, w); /* done = True; */ break; } } w->target_x = x + w->lbearing; w->target_y = y - w->ascent; x += w->rbearing + space; se->width = x; if (se->nwords >= (array_size - 1)) { array_size += 100; se->words = (word **) realloc (se->words, array_size * sizeof(*se->words)); if (!se->words) { fprintf (stderr, "%s: out of memory (%d words)\n", progname, array_size); exit (1); } } se->words[se->nwords++] = w; } se->width -= space; switch (s->mode) { case PAGE: align_line (s, se, line_start, x, right); if (se->move_chars_p) split_words (s, se); scatter_sentence (s, se); shuffle_words (s, se); break; case SCROLL: aim_sentence (s, se); break; default: abort(); break; } # ifdef DEBUG if (s->debug_p) { fprintf (stderr, "%s: sentence %d:", progname, se->id); for (i = 0; i < se->nwords; i++) fprintf (stderr, " %s", se->words[i]->text); fprintf (stderr, "\n"); } # endif }