static automap_path *automap_find_path(loc_node *location, loc_node *dest, BOOL by_walking) { automap_path *path = NULL; automap_path *rev; automap_path newnode; loc_node *p; /* Find the distances of all nodes from dest */ n_hash_enumerate(&rooms, make_distant); automap_calc_distances(dest, 0, by_walking); /* If dest isn't reachable, location's distance will still be infinite */ if(location->dist == INFINITY) return NULL; /* At each step, go toward a nearer node 'till we're there */ p = location; while(p != dest) { unsigned i; unsigned best_dir; glui32 best_dist = INFINITY; loc_node *best_node = NULL; unsigned maxdir = by_walking ? NUM_EXITS : NUM_DIRS; for(i = 0; i < maxdir; i++) { loc_node *thisdest; if(by_walking) thisdest = p->exits[i]; else thisdest = automap_edge_follow(p, i); if(thisdest && thisdest->dist < best_dist) { best_dir = i; best_dist = thisdest->dist; best_node = thisdest; } } if(!best_node) { n_show_error(E_SYSTEM, "couldn't find path there", 0); return NULL; } newnode.loc = p; newnode.dir = best_dir; LEadd(path, newnode); p = best_node; } rev = NULL; while(path) { LEadd(rev, *path); LEremove(path); } return rev; }
static void automap_find_cycles(loc_node *location, automap_path *curpath) { unsigned i; location->touched = TRUE; for(i = 0; i < NUM_DIRS; i++) { loc_node *thisdest = automap_edge_follow(location, i); if(thisdest && thisdest->found) { automap_path newnode; newnode.dir = i; newnode.loc = location; LEadd(curpath, newnode); if(thisdest->touched) { /* Found a cycle! */ int cyclelength = 0; automap_path *p; cycleequation *cycle = NULL; cycleequation newcycle; for(p = curpath; p; p=p->next) { int dir = p->dir; newcycle.var = &(p->loc->outgoing[dir]->guess_length); newcycle.min = &(p->loc->outgoing[dir]->min_length); newcycle.xcoefficient = dirways[dir].deltax; newcycle.ycoefficient = dirways[dir].deltay; LEadd(cycle, newcycle); cyclelength++; if(p->loc == thisdest) { /* Found the relevant endpoint */ if(cyclelength <= 2) /* Ignore two nodes going to each other */ LEdestroy(cycle); else automap_add_cycle(cycle); /* automap_add_cycle gets ownership */ break; } } if(!p) { /* The cycle had already been found */ LEdestroy(cycle); } } else { automap_find_cycles(thisdest, curpath); } LEremove(curpath); } } }
static void automap_remember_interference(loc_node *a, loc_node *b) { /* interlist *p; LEsearch(interferences, p, (p->a==a && p->b==b) || (p->a==b && p->b==a)); if(!p) {*/ interlist newnode; newnode.a = a; newnode.b = b; LEadd(interferences, newnode); /* }*/ }
static edge *automap_new_edge(loc_node *src, loc_node *dest, BOOL is_oneway) { edgelist newedge; newedge.node = n_malloc(sizeof(edge)); newedge.node->dest[0] = src; newedge.node->dest[1] = dest; newedge.node->is_oneway = is_oneway; newedge.node->touched = FALSE; newedge.node->min_length = is_oneway ? 4 : 2; newedge.node->guess_length = is_oneway ? 4 : 2; LEadd(all_edges, newedge); return newedge.node; }
static zword smart_tokeniser(zword dictionarytable, const char *text, unsigned length, BOOL is_begin) { zword word_num = 0; unsigned tlength = (length < 12) ? length : 12; char tbuffer[13]; /* Letter replacements are tried in this order - */ const char fixmeletters[] = "abcdefghijklmnopqrstuvwxyz"; /* char fixmeletters[] = "etaonrishdlfcmugpywbvkxjqz"; */ word_num = find_word(dictionarytable, text, length); /* Some game files don't contain abbreviations for common commands */ if(!word_num && do_expand && length == 1 && is_begin) { const char * const abbrevs[26] = { "a", "b", "close", "down", "east", "f", "again", "h", "inventory", "j", "attack", "look", "m", "north", "oops", "open", "quit", "drop", "south", "take", "up", "v", "west", "examine", "yes", "wait" }; if('a' <= text[0] && text[0] <= 'z') { strcpy(tbuffer, abbrevs[text[0] - 'a']); tlength = strlen(tbuffer); word_num = find_word(dictionarytable, tbuffer, tlength); } } /* Check for various typing errors */ /* Don't attempt typo correction in very short words */ if(do_spell_correct && length >= 3) { if(!word_num) { /* Check for transposes */ /* To fix, try all possible transposes */ unsigned position; for(position = 1; position < tlength; position++) { unsigned s; for(s = 0; s < tlength; s++) tbuffer[s] = text[s]; tbuffer[position - 1] = text[position]; tbuffer[position] = text[position - 1]; word_num = find_word(dictionarytable, tbuffer, tlength); if(word_num) break; } } if(!word_num) { /* Check for deletions */ /* To fix, try all possible insertions */ unsigned position; for(position = 0; position <= tlength; position++) { unsigned s; for(s = 0; s < position; s++) /* letters before the insertion */ tbuffer[s] = text[s]; for(s = position; s < tlength; s++) /* after the insertion */ tbuffer[s + 1] = text[s]; /* try each letter */ for(s = 0; s < sizeof(fixmeletters); s++) { tbuffer[position] = fixmeletters[s]; word_num = find_word(dictionarytable, tbuffer, tlength + 1); if(word_num) break; } if(word_num) { tlength++; break; } } } if(!word_num) { /* Check for insertions */ /* To fix, try all possible deletions */ unsigned position; for(position = 0; position < tlength; position++) { unsigned s; for(s = 0; s < position; s++) /* letters before the deletion */ tbuffer[s] = text[s]; for(s = position + 1; s < tlength; s++) /* after the deletion */ tbuffer[s - 1] = text[s]; word_num = find_word(dictionarytable, tbuffer, tlength - 1); if(word_num) { tlength--; break; } } } if(!word_num) { /* Check for substitutions */ /* To fix, try all possible substitutions */ unsigned position; for(position = 0; position < tlength; position++) { unsigned s; for(s = 0; s < tlength; s++) tbuffer[s] = text[s]; /* try each letter */ for(s = 0; s < sizeof(fixmeletters); s++) { tbuffer[position] = fixmeletters[s]; word_num = find_word(dictionarytable, tbuffer, tlength); if(word_num) break; } if(word_num) break; } } } /* Report any corrections made */ if(word_num) { struct Typocorrection *p; char original[13], changedto[13]; n_strncpy(original, text, 13); n_strncpy(changedto, tbuffer, 13); if(length < 13) original[length] = 0; if(tlength < 13) changedto[tlength] = 0; LEsearch(recent_corrections, p, ((n_strncmp(p->original, original, 13) == 0) && (n_strncmp(p->changedto, changedto, 13) == 0))); /* Only print a correction if it hasn't yet been reported this turn */ if(!p) { struct Typocorrection newcorrection; n_strncpy(newcorrection.original, original, 13); n_strncpy(newcorrection.changedto, changedto, 13); LEadd(recent_corrections, newcorrection); set_glk_stream_current(); if(allow_output) { glk_put_char('['); w_glk_put_buffer(text, length); w_glk_put_string(" -> "); w_glk_put_buffer(tbuffer, tlength); glk_put_char(']'); glk_put_char(10); } } } return word_num; }
BOOL saveundo(BOOL in_instruction) { move_difference newdiff; strid_t stack; stream_result_t poo; if(!allow_saveundo) return TRUE; /* In games which provide @save_undo, we will have already issued a faked saveundo before the first @save_undo hits, since there hadn't been any @save_undo before the first read line. So when this happens, wipe the fake saveundo in favor of the real one */ if(in_instruction && movelist && !movelist->next && !movelist->PC_in_instruction) init_undo(); if(!quetzal_diff(z_memory, prevstate, dynamic_size, &newdiff.delta, &newdiff.deltalength, TRUE)) return FALSE; #ifdef PARANOID { char *newmem = (char *) n_malloc(dynamic_size); n_memcpy(newmem, prevstate, dynamic_size); quetzal_undiff(newmem, dynamic_size, newdiff.delta, newdiff.deltalength, TRUE); if(n_memcmp(z_memory, newmem, dynamic_size)) { n_show_error(E_SAVE, "save doesn't match itself", 0); } n_free(newmem); } #endif newdiff.PC = PC; newdiff.oldPC = oldPC; newdiff.PC_in_instruction = in_instruction; newdiff.stacklength = get_quetzal_stack_size(); newdiff.stackchunk = (zbyte *) n_malloc(newdiff.stacklength); stack = glk_stream_open_memory((char *) newdiff.stackchunk, newdiff.stacklength, filemode_Write, 0); if(!stack) { n_free(newdiff.delta); n_free(newdiff.stackchunk); return FALSE; } if(!quetzal_stack_save(stack)) { glk_stream_close(stack, NULL); n_free(newdiff.delta); n_free(newdiff.stackchunk); return FALSE; } glk_stream_close(stack, &poo); if(poo.writecount != newdiff.stacklength) { n_show_error(E_SAVE, "incorrect stack size assessment", poo.writecount); n_free(newdiff.delta); n_free(newdiff.stackchunk); return FALSE; } while(move_index-- > 0) { n_free(movelist->delta); n_free(movelist->stackchunk); LEremove(movelist); } LEadd(movelist, newdiff); move_index++; n_memcpy(prevstate, z_memory, dynamic_size); has_done_save_undo = TRUE; return TRUE; }