diff options
author | Paul Gilbert | 2019-05-11 11:09:36 +1000 |
---|---|---|
committer | Paul Gilbert | 2019-05-11 11:11:23 +1000 |
commit | c1f8bd88232c026af207923a4f53bbfca439de13 (patch) | |
tree | a950081348e903e3e801e66e9458e43e40225206 /engines/glk | |
parent | 0b2346c1f14d94efa1264aadef5bf13c1f15ddef (diff) | |
download | scummvm-rg350-c1f8bd88232c026af207923a4f53bbfca439de13.tar.gz scummvm-rg350-c1f8bd88232c026af207923a4f53bbfca439de13.tar.bz2 scummvm-rg350-c1f8bd88232c026af207923a4f53bbfca439de13.zip |
GLK: HUGO: Replace contents of hemisc
Unlike initally where I was ripping out parts of the file and making
code changes, this version is intended to be more identical to the
original, except for the functions being made class methods. This
should make it easier to apply any further upstream code changes to
the codebase in the future
Diffstat (limited to 'engines/glk')
-rw-r--r-- | engines/glk/hugo/hemisc.cpp | 2497 | ||||
-rw-r--r-- | engines/glk/hugo/hugo.cpp | 7 | ||||
-rw-r--r-- | engines/glk/hugo/hugo.h | 53 | ||||
-rw-r--r-- | engines/glk/hugo/hugo_defines.h | 2 | ||||
-rw-r--r-- | engines/glk/hugo/hugo_types.h | 4 |
5 files changed, 1551 insertions, 1012 deletions
diff --git a/engines/glk/hugo/hemisc.cpp b/engines/glk/hugo/hemisc.cpp index ac3a0d4dd0..c5a77803f7 100644 --- a/engines/glk/hugo/hemisc.cpp +++ b/engines/glk/hugo/hemisc.cpp @@ -26,108 +26,109 @@ namespace Glk { namespace Hugo { void Hugo::AP(const char *a) { - char sticky = false, skipspchar = false, startofline = 0; - int i, alen, plen, cwidth; - char c = 0; /* current character */ + char sticky = false, skipspchar = false, startofline = 0; + int i, alen, plen, cwidth; + char c = 0; /* current character */ #ifdef USE_SMARTFORMATTING - char lastc = 0; /* for smart formatting */ + char lastc = 0; /* for smart formatting */ #endif - static int lastfcolor = 16, lastbgcolor = 17; - static int lastfont = NORMAL_FONT; - static int thisline = 0; /* width in pixels or characters */ - static int linebreaklen = 0, linebreak = 0; - int tempfont; - char printed_something = false; + static int lastfcolor = 16, lastbgcolor = 17; + static int lastfont = NORMAL_FONT; + static int thisline = 0; /* width in pixels or characters */ + static int linebreaklen = 0, linebreak = 0; + int tempfont; + char printed_something = false; #ifdef USE_TEXTBUFFER - int bufferfont = currentfont; + int bufferfont = currentfont; #endif - /* Shameless little trick to override control characters in engine- - printed text, such as MS-DOS filenames that contain '\'s: - */ - if (a[0] == NO_CONTROLCHAR) - { - skipspchar = true; - a++; - } - /* Semi-colon overrides LF */ - if ((strlen(a) >= 2) && a[strlen(a) - 1] == ';' && a[strlen(a) - 2] == '\\') - { - sticky = true; - } + /* Shameless little trick to override control characters in engine- + printed text, such as MS-DOS filenames that contain '\'s: + */ + if (a[0]==NO_CONTROLCHAR) + { + skipspchar = true; + a++; + } + + /* Semi-colon overrides LF */ + if ((strlen(a)>=2) && a[strlen(a)-1]==';' && a[strlen(a)-2]=='\\') + { + sticky = true; + } - if (hugo_strlen(pbuffer)) - printed_something = true; + if (hugo_strlen(pbuffer)) + printed_something = true; - plen = strlen(pbuffer); - if (plen == 0) - { - thisline = 0; - linebreak = 0; - linebreaklen = 0; - lastfont = currentfont; - startofline = true; + plen = strlen(pbuffer); + if (plen==0) + { + thisline = 0; + linebreak = 0; + linebreaklen = 0; + lastfont = currentfont; + startofline = true; #ifdef USE_TEXTBUFFER - bufferbreak = 0; - bufferbreaklen = 0; + bufferbreak = 0; + bufferbreaklen = 0; #endif #ifdef USE_SMARTFORMATTING - leftquote = true; + leftquote = true; #endif - } + } - /* Check for color changes */ - if ((a[0]) && (lastfcolor != fcolor || lastbgcolor != bgcolor || startofline)) - { - if (plen >= MAXBUFFER * 2 - 3) FatalError(OVERFLOW_E); - pbuffer[plen++] = COLOR_CHANGE; - pbuffer[plen++] = (char)(fcolor + 1); - pbuffer[plen++] = (char)(bgcolor + 1); - pbuffer[plen] = '\0'; - lastfcolor = fcolor; - lastbgcolor = bgcolor; - } + /* Check for color changes */ + if ((a[0]) && (lastfcolor!=fcolor || lastbgcolor!=bgcolor || startofline)) + { + if (plen >= MAXBUFFER*2-3) FatalError(OVERFLOW_E); + pbuffer[plen++] = COLOR_CHANGE; + pbuffer[plen++] = (char)(fcolor+1); + pbuffer[plen++] = (char)(bgcolor+1); + pbuffer[plen] = '\0'; + lastfcolor = fcolor; + lastbgcolor = bgcolor; + } - /* Check for font changes--since fonts can only get changed - by printing, we don't check lastfont */ - if ((a[0]) && startofline) - { - if (plen >= MAXBUFFER * 2 - 2) FatalError(OVERFLOW_E); - pbuffer[plen++] = FONT_CHANGE; - pbuffer[plen++] = (char)(currentfont + 1); - pbuffer[plen] = '\0'; - lastfont = currentfont; - } + /* Check for font changes--since fonts can only get changed + by printing, we don't check lastfont */ + if ((a[0]) && startofline) + { + if (plen >= MAXBUFFER*2-2) FatalError(OVERFLOW_E); + pbuffer[plen++] = FONT_CHANGE; + pbuffer[plen++] = (char)(currentfont+1); + pbuffer[plen] = '\0'; + lastfont = currentfont; + } - /* Begin by looping through the entire provided string: */ + /* Begin by looping through the entire provided string: */ - alen = (int)strlen(a); - if (sticky) - alen -= 2; + alen = (int)strlen(a); + if (sticky) + alen -= 2; - /* Not printing any actual text, so we won't need to go through - queued font changes - */ - if (alen == 0) - lastfont = currentfont; + /* Not printing any actual text, so we won't need to go through + queued font changes + */ + if (alen==0) + lastfont = currentfont; - for (i = 0; i<alen; i++) - { - c = a[i]; + for (i=0; i<alen; i++) + { + c = a[i]; + + /* Left-justification */ + if (thisline==0 && c==' ' && !textto && currentpos==0) + continue; - /* Left-justification */ - if (thisline == 0 && c == ' ' && !textto && currentpos == 0) - continue; + /* First check control characters */ + if (c=='\\' && !skipspchar) + { + c = a[++i]; - /* First check control characters */ - if (c == '\\' && !skipspchar) + switch (c) { - c = a[++i]; - - switch (c) - { case 'n': { c = '\n'; @@ -171,7 +172,7 @@ void Hugo::AP(const char *a) { case 'u': { currentfont &= ~UNDERLINE_FONT; - AddFontCode: +AddFontCode: if (!textto) { int m, n; @@ -180,43 +181,43 @@ void Hugo::AP(const char *a) { if (!printed_something) { - for (m = 0; m<plen;) + for (m=0; m<plen;) { - if (pbuffer[m] == FONT_CHANGE) + if (pbuffer[m]==FONT_CHANGE) { - for (n = m; n<plen - 2; n++) + for (n=m; n<plen-2; n++) { - pbuffer[n] = pbuffer[n + 2]; + pbuffer[n] = pbuffer[n+2]; } - plen -= 2; + plen-=2; pbuffer[plen] = '\0'; lastfont = currentfont; } - else if (pbuffer[m] == COLOR_CHANGE) - m += 3; + else if (pbuffer[m]==COLOR_CHANGE) + m+=3; else break; } } #ifdef USE_TEXTBUFFER - if (hugo_strlen(pbuffer + bufferbreak) == 0) + if (hugo_strlen(pbuffer+bufferbreak)==0) bufferfont = currentfont; #endif - if (plen >= MAXBUFFER * 2 - 2) FatalError(OVERFLOW_E); - pbuffer[plen + 2] = '\0'; - pbuffer[plen + 1] = (char)(currentfont + 1); + if (plen >= MAXBUFFER*2-2) FatalError(OVERFLOW_E); + pbuffer[plen+2] = '\0'; + pbuffer[plen+1] = (char)(currentfont+1); pbuffer[plen] = FONT_CHANGE; - plen += 2; + plen+=2; /* Convert full if font height changes, since - the amount of used screen real estate for - this particular font (in terms of lines) - will have changed: + the amount of used screen real estate for + this particular font (in terms of lines) + will have changed: */ ratio = (double)lineheight; hugo_font(currentfont); ratio /= (double)lineheight; - newfull = (int)(((double)full)*ratio + 0.5); + newfull = (int)(((double)full)*ratio+0.5); if (newfull) full = newfull; } continue; @@ -229,618 +230,701 @@ void Hugo::AP(const char *a) { } default: c = SpecialChar(a, &i); - } - } - else if (game_version <= 22) - { - if (c == '~') - c = '\"'; - else if (c == '^') - c = '\n'; } + } + else if (game_version<=22) + { + if (c=='~') + c = '\"'; + else if (c=='^') + c = '\n'; + } - /* Add the new character */ + /* Add the new character */ - /* Text may be sent to an address in the array table instead - of being output to the screen - */ - if (textto) - { - /* space for array length */ - int n = (game_version>23) ? 2 : 0; + /* Text may be sent to an address in the array table instead + of being output to the screen + */ + if (textto) + { + /* space for array length */ + int n = (game_version>23)?2:0; - if (c == '\n') - { - SETMEM(arraytable * 16L + textto * 2 + n, 0); - textto++; - } - else if ((unsigned char)c >= ' ') - { - SETMEM(arraytable * 16L + textto * 2 + n, c); - textto++; - } - /* Add a terminating zero in case we don't - print any more to the array */ - SETMEM(arraytable * 16L + textto * 2 + n, 0); + if (c=='\n') + { + SETMEM(arraytable*16L + textto*2 + n, 0); + textto++; + } + else if ((unsigned char)c >= ' ') + { + SETMEM(arraytable*16L + textto*2 + n, c); + textto++; + } + /* Add a terminating zero in case we don't + print any more to the array */ + SETMEM(arraytable*16L + textto*2 + n, 0); - if (i >= alen) return; + if (i >= alen) return; - continue; /* back to for (i=0; i<slen; i++) */ - } + continue; /* back to for (i=0; i<slen; i++) */ + } - printed_something = true; + printed_something = true; - /* Handle in-text newlines */ - if (c == '\n') - { - hugo_font(currentfont = lastfont); + /* Handle in-text newlines */ + if (c=='\n') + { + hugo_font(currentfont = lastfont); #ifdef USE_TEXTBUFFER - TB_AddWord(pbuffer + bufferbreak, - current_text_x + bufferbreaklen, - current_text_y, - current_text_x + thisline - 1, - current_text_y + lineheight - 1); -#endif - Printout(pbuffer); - lastfont = currentfont; + TB_AddWord(pbuffer+bufferbreak, + current_text_x+bufferbreaklen, + current_text_y, + current_text_x+thisline-1, + current_text_y+lineheight-1); +#endif + Printout(pbuffer, 0); + lastfont = currentfont; #ifdef USE_TEXTBUFFER - bufferfont = currentfont; - bufferbreak = 0; - bufferbreaklen = 0; -#endif - strcpy(pbuffer, ""); - plen = 0; - linebreak = 0; - linebreaklen = 0; - thisline = 0; + bufferfont = currentfont; + bufferbreak = 0; + bufferbreaklen = 0; +#endif + strcpy(pbuffer, ""); + plen = 0; + linebreak = 0; + linebreaklen = 0; + thisline = 0; #ifdef USE_SMARTFORMATTING - leftquote = true; - lastc = '\n'; + leftquote = true; + lastc = '\n'; #endif - pbuffer[plen++] = COLOR_CHANGE; - pbuffer[plen++] = (char)(fcolor + 1); - pbuffer[plen++] = (char)(bgcolor + 1); - pbuffer[plen] = '\0'; + pbuffer[plen++] = COLOR_CHANGE; + pbuffer[plen++] = (char)(fcolor+1); + pbuffer[plen++] = (char)(bgcolor+1); + pbuffer[plen] = '\0'; - continue; - } + continue; + } #ifdef USE_SMARTFORMATTING - /* Smart formatting only for non-fixed fonts */ - if ((currentfont & PROP_FONT) && smartformatting) + /* Smart formatting only for non-fixed fonts */ + if ((currentfont & PROP_FONT) && smartformatting) + { + if ((!strncmp(a+i, "--", 2)) && lastc!='-' && strncmp(a+i, "---", 3)) { - if ((!strncmp(a + i, "--", 2)) && lastc != '-' && strncmp(a + i, "---", 3)) - { - lastc = '-'; - c = (char)151; - i++; - leftquote = false; - } - else if (c == '\"') - { - if (leftquote) - c = (char)147; - else - c = (char)148; - leftquote = false; - lastc = c; - } - else if (c == '\'') - { - if (leftquote) - c = (char)145; - else - c = (char)146; - leftquote = false; - lastc = c; - } + lastc = '-'; + c = (char)151; + i++; + leftquote = false; + } + else if (c=='\"') + { + if (leftquote) + c = (char)147; else - { - if (c == ' ') - leftquote = true; - else - leftquote = false; - lastc = c; - } + c = (char)148; + leftquote = false; + lastc = c; + } + else if (c=='\'') + { + if (leftquote) + c = (char)145; + else + c = (char)146; + leftquote = false; + lastc = c; + } + else + { + if (c==' ') + leftquote = true; + else + leftquote = false; + lastc = c; } + } #endif - /* Add the new character to the printing buffer */ - if (plen >= MAXBUFFER * 2 - 1) FatalError(OVERFLOW_E); - pbuffer[plen + 1] = '\0'; - pbuffer[plen] = c; - plen++; - - cwidth = hugo_charwidth(c); + /* Add the new character to the printing buffer */ + if (plen >= MAXBUFFER*2-1) FatalError(OVERFLOW_E); + pbuffer[plen+1] = '\0'; + pbuffer[plen] = c; + plen++; - /* Check to see if we've overrun the current line */ + cwidth = hugo_charwidth(c); - if (thisline + cwidth + currentpos > physical_windowwidth) - { - char t; + /* Check to see if we've overrun the current line */ - if (!linebreak) - { - linebreak = plen - 1; - linebreaklen = thisline; - } + if (thisline+cwidth+currentpos > physical_windowwidth) + { + char t; - t = pbuffer[linebreak]; - pbuffer[linebreak] = '\0'; - - tempfont = currentfont; - hugo_font(currentfont = lastfont); - Printout(pbuffer); - lastfont = currentfont; - hugo_font(currentfont = tempfont); - - pbuffer[linebreak] = t; - plen = strlen(pbuffer + linebreak); - memmove(pbuffer, pbuffer + linebreak, plen + 1); - thisline = thisline - linebreaklen; - linebreak = 0; - linebreaklen = 0; - startofline = 0; -#ifdef USE_TEXTBUFFER - bufferbreak = 0; - bufferbreaklen = 0; -#endif + if (!linebreak) + { + linebreak = plen-1; + linebreaklen = thisline; } - thisline += cwidth; + t = pbuffer[linebreak]; + pbuffer[linebreak] = '\0'; + tempfont = currentfont; + hugo_font(currentfont = lastfont); + Printout(pbuffer, linebreak); + lastfont = currentfont; + hugo_font(currentfont = tempfont); + + pbuffer[linebreak] = t; + plen = strlen(pbuffer+linebreak); + memmove(pbuffer, pbuffer+linebreak, plen + 1); + thisline = thisline - linebreaklen; + linebreak = 0; + linebreaklen = 0; + startofline = 0; #ifdef USE_TEXTBUFFER - if ((c == ' ' || c == FORCED_SPACE) || - (c == '/' && a[i + 1] != '/') || (c == '-' && a[i + 1] != '-')) - { - TB_AddWord(pbuffer + bufferbreak, - current_text_x + bufferbreaklen, - current_text_y, - current_text_x + thisline - 1, - current_text_y + lineheight - 1); - - bufferbreak = plen; - bufferbreaklen = thisline; - bufferfont = currentfont; - } + bufferbreak = 0; + bufferbreaklen = 0; #endif - if ((c == ' ') || (c == '/' && a[i + 1] != '/') || (c == '-' && a[i + 1] != '-')) - { - linebreak = plen, linebreaklen = thisline; - } } + thisline += cwidth; + #ifdef USE_TEXTBUFFER - if (!sticky || alen > 1) + if ((c==' ' || c==FORCED_SPACE) || + (c=='/' && a[i+1]!='/') || (c=='-' && a[i+1]!='-')) { - tempfont = currentfont; - currentfont = bufferfont; - - TB_AddWord(pbuffer + bufferbreak, - current_text_x + bufferbreaklen, + TB_AddWord(pbuffer+bufferbreak, + current_text_x+bufferbreaklen, current_text_y, - current_text_x + thisline - 1, - current_text_y + lineheight - 1); + current_text_x+thisline-1, + current_text_y+lineheight-1); bufferbreak = plen; bufferbreaklen = thisline; - currentfont = tempfont; + bufferfont = currentfont; } #endif - if (!sticky) + if ((c==' ') || (c=='/' && a[i+1]!='/') || (c=='-' && a[i+1]!='-')) { - hugo_font(currentfont = lastfont); - Printout(pbuffer); - lastfont = currentfont; - strcpy(pbuffer, ""); - linebreak = 0; - linebreaklen = 0; - thisline = 0; - plen = 0; + linebreak = plen, linebreaklen = thisline; + } + } + #ifdef USE_TEXTBUFFER - bufferbreak = 0; - bufferbreaklen = 0; + if (!sticky || alen > 1) + { + tempfont = currentfont; + currentfont = bufferfont; + + TB_AddWord(pbuffer+bufferbreak, + current_text_x+bufferbreaklen, + current_text_y, + current_text_x+thisline-1, + current_text_y+lineheight-1); + + bufferbreak = plen; + bufferbreaklen = thisline; + currentfont = tempfont; + } +#endif + if (!sticky) + { + hugo_font(currentfont = lastfont); + Printout(pbuffer, 0); + lastfont = currentfont; + strcpy(pbuffer, ""); + linebreak = 0; + linebreaklen = 0; + thisline = 0; + plen = 0; +#ifdef USE_TEXTBUFFER + bufferbreak = 0; + bufferbreaklen = 0; #endif #ifdef USE_SMARTFORMATTING - leftquote = true; + leftquote = true; #endif - } } +} int Hugo::CallRoutine(unsigned int addr) { - int arg, i; - int val; - int templocals[MAXLOCALS], temppass[MAXLOCALS]; - int temp_stack_depth; - long tempptr; - int potential_tail_recursion = tail_recursion; + int arg, i; + int val; + int templocals[MAXLOCALS], temppass[MAXLOCALS]; + int temp_stack_depth; + long tempptr; + int potential_tail_recursion = tail_recursion; #if defined (DEBUGGER) - int tempdbnest; + int tempdbnest; #endif - arg = 0; - tail_recursion = 0; + arg = 0; + tail_recursion = 0; - /* Pass local variables to routine, if specified */ - if (MEM(codeptr) == OPEN_BRACKET_T) + /* Pass local variables to routine, if specified */ + if (MEM(codeptr)==OPEN_BRACKET_T) + { + codeptr++; + while (MEM(codeptr) != CLOSE_BRACKET_T) { - codeptr++; - while (MEM(codeptr) != CLOSE_BRACKET_T) + if (arg) { - if (arg) - { - for (i = 0; i<arg; i++) - temppass[i] = passlocal[i]; - } - - passlocal[arg++] = GetValue(); + for (i=0; i<arg; i++) + temppass[i] = passlocal[i]; + } - if (arg > 1) - { - for (i = 0; i<arg - 1; i++) - passlocal[i] = temppass[i]; - } + passlocal[arg++] = GetValue(); - if (MEM(codeptr) == COMMA_T) codeptr++; + if (arg > 1) + { + for (i=0; i<arg-1; i++) + passlocal[i] = temppass[i]; } - codeptr++; - } - /* TAIL_RECURSION_ROUTINE if we came from a routine call immediately - following a 'return' statement... - */ - tail_recursion = potential_tail_recursion; - if (tail_recursion == TAIL_RECURSION_ROUTINE && MEM(codeptr) == EOL_T) - { - tail_recursion_addr = (long)addr*address_scale; - PassLocals(arg); - return 0; - } - /* ...but if we're not immediately followed by and end-of-line marker, - cancel the pending tail-recursion - */ - else - { - tail_recursion = 0; + if (MEM(codeptr)==COMMA_T) codeptr++; } + codeptr++; + } - for (i = 0; i<MAXLOCALS; i++) - templocals[i] = var[MAXGLOBALS + i]; + /* TAIL_RECURSION_ROUTINE if we came from a routine call immediately + following a 'return' statement... + */ + tail_recursion = potential_tail_recursion; + if (tail_recursion==TAIL_RECURSION_ROUTINE && MEM(codeptr)==EOL_T) + { + tail_recursion_addr = (long)addr*address_scale; PassLocals(arg); + return 0; + } + /* ...but if we're not immediately followed by and end-of-line marker, + cancel the pending tail-recursion + */ + else + { + tail_recursion = 0; + } - temp_stack_depth = stack_depth; + for (i=0; i<MAXLOCALS; i++) + templocals[i] = var[MAXGLOBALS+i]; + PassLocals(arg); - SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0); + temp_stack_depth = stack_depth; - tempptr = codeptr; /* store calling address */ - ret = 0; + SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0); + + tempptr = codeptr; /* store calling address */ + ret = 0; #if defined (DEBUGGER) - tempdbnest = dbnest; - DebugRunRoutine((long)addr*address_scale); - dbnest = tempdbnest; + tempdbnest = dbnest; + DebugRunRoutine((long)addr*address_scale); + dbnest = tempdbnest; #else - RunRoutine((long)addr*address_scale); + RunRoutine((long)addr*address_scale); #endif - retflag = 0; - val = ret; - codeptr = tempptr; + retflag = 0; + val = ret; + codeptr = tempptr; - stack_depth = temp_stack_depth; + stack_depth = temp_stack_depth; - for (i = 0; i<MAXLOCALS; i++) - var[MAXGLOBALS + i] = templocals[i]; + for (i=0; i<MAXLOCALS; i++) + var[MAXGLOBALS+i] = templocals[i]; - return val; - } + return val; +} void Hugo::ContextCommand() { - unsigned int n; + unsigned int n; - ContextCommandLoop: +ContextCommandLoop: - codeptr++; - - n = GetValue(); + codeptr++; + + n = GetValue(); #if !defined (COMPILE_V25) - if (n == 0) - { - context_commands = 0; - } - else if (context_commands < MAX_CONTEXT_COMMANDS) - { - char *cc; + if (n==0) + { + context_commands = 0; + } + else if (context_commands < MAX_CONTEXT_COMMANDS) + { + char *cc; - strncpy(context_command[context_commands], cc = GetWord(n), 64); - context_command[context_commands][63] = '\0'; - if (strlen(cc) >= 64) - sprintf(context_command[context_commands] + 60, "..."); - context_commands++; - } -#endif - if (Peek(codeptr) == COMMA_T) goto ContextCommandLoop; - codeptr++; + strncpy(context_command[context_commands], cc = GetWord(n), 64); + context_command[context_commands][63] = '\0'; + if (strlen(cc)>=64) + sprintf(context_command[context_commands]+60, "..."); + context_commands++; } +#endif + if (Peek(codeptr)==COMMA_T) goto ContextCommandLoop; + codeptr++; +} unsigned int Hugo::Dict() { - int i, len = 256; - unsigned int arr; - unsigned int pos = 2, loc; + int i, len = 256; + unsigned int arr; + unsigned int pos = 2, loc; - codeptr += 2; /* "(" */ + codeptr += 2; /* "(" */ - if (MEM(codeptr) == PARSE_T || MEM(codeptr) == WORD_T) - strcpy(line, GetWord(GetValue())); - else + if (MEM(codeptr)==PARSE_T || MEM(codeptr)==WORD_T) + strcpy(line, GetWord(GetValue())); + else + { + /* Get the array address to read the to-be- + created dictionary entry from: + */ + arr = GetValue(); + if (game_version>=22) { - /* Get the array address to read the to-be- - created dictionary entry from: + /* Convert the address to a word + value: */ - arr = GetValue(); - if (game_version >= 22) - { - /* Convert the address to a word - value: - */ - arr *= 2; - - if (game_version >= 23) - /* space for array length */ - arr += 2; - } + arr*=2; - defseg = arraytable; - for (i = 0; i<len && PeekWord(arr + i * 2) != 0; i++) - line[i] = (char)PeekWord(arr + i * 2); - defseg = gameseg; - line[i] = '\0'; + if (game_version>=23) + /* space for array length */ + arr+=2; } - if (Peek(codeptr) == COMMA_T) codeptr++; - len = GetValue(); + defseg = arraytable; + for (i=0; i<len && PeekWord(arr+i*2)!=0; i++) + line[i] = (char)PeekWord(arr+i*2); + defseg = gameseg; + line[i] = '\0'; + } - if ((loc = FindWord(line)) != UNKNOWN_WORD) return loc; + if (Peek(codeptr)==COMMA_T) codeptr++; + len = GetValue(); - defseg = dicttable; + if ((loc = FindWord(line))!=UNKNOWN_WORD) return loc; - for (i = 1; i <= dictcount; i++) - pos += Peek(pos) + 1; + defseg = dicttable; - loc = pos - 2; + for (i=1; i<=dictcount; i++) + pos += Peek(pos) + 1; - if ((long)(pos + strlen(line)) > (long)(codeend - dicttable * 16L)) - { + loc = pos - 2; + + if ((long)(pos+strlen(line)) > (long)(codeend-dicttable*16L)) + { #ifdef DEBUGGER - sprintf(debug_line, "$MAXDICTEXTEND dictionary space exceeded"); - RuntimeWarning(debug_line); + sprintf(debug_line, "$MAXDICTEXTEND dictionary space exceeded"); + RuntimeWarning(debug_line); #endif - defseg = gameseg; - return 0; - } + defseg = gameseg; + return 0; + } - Poke(pos++, (unsigned char)strlen(line)); - for (i = 0; i<(int)strlen(line) && i<len; i++) - Poke(pos++, (unsigned char)(line[i] + CHAR_TRANSLATION)); - PokeWord(0, ++dictcount); + Poke(pos++, (unsigned char)strlen(line)); + for (i=0; i<(int)strlen(line) && i<len; i++) + Poke(pos++, (unsigned char)(line[i]+CHAR_TRANSLATION)); + PokeWord(0, ++dictcount); - defseg = gameseg; + defseg = gameseg; - SaveUndo(DICT_T, strlen(line), 0, 0, 0); + SaveUndo(DICT_T, strlen(line), 0, 0, 0); - return loc; - } + return loc; +} -void Hugo::FatalError(int n){ +void Hugo::FatalError(int n) { char fatalerrorline[64]; +#if defined (DEBUGGER) + hugo_stopmusic(); + hugo_stopsample(); + + /* If the Debugger has already issued an error, it will + try to recover instead of issuing a stream of + identical errors. + */ + if (runtime_error) return; +#else hugo_cleanup_screen(); +#endif switch (n) { - case MEMORY_E: - {sprintf(line, "Out of memory\n"); - break; } + case MEMORY_E: + {sprintf(line, "Out of memory\n"); + break;} - case OPEN_E: - {sprintf(line, "Cannot open file\n"); - break; } + case OPEN_E: + {sprintf(line, "Cannot open file\n"); + break;} - case READ_E: - {sprintf(line, "Cannot read from file\n"); - break; } + case READ_E: + {sprintf(line, "Cannot read from file\n"); + break;} - case WRITE_E: - {sprintf(line, "Cannot write to save file\n"); - break; } + case WRITE_E: + {sprintf(line, "Cannot write to save file\n"); + break;} - case EXPECT_VAL_E: - {sprintf(line, "Expecting value at $%s\n", PrintHex(codeptr)); - break; } + case EXPECT_VAL_E: + {sprintf(line, "Expecting value at $%s\n", PrintHex(codeptr)); + break;} - case UNKNOWN_OP_E: - {sprintf(line, "Unknown operation at $%s\n", PrintHex(codeptr)); - break; } + case UNKNOWN_OP_E: + {sprintf(line, "Unknown operation at $%s\n", PrintHex(codeptr)); + break;} - case ILLEGAL_OP_E: - {sprintf(line, "Illegal operation at $%s\n", PrintHex(codeptr)); - break; } + case ILLEGAL_OP_E: + {sprintf(line, "Illegal operation at $%s\n", PrintHex(codeptr)); + break;} - case OVERFLOW_E: - {sprintf(line, "Overflow at $%s\n", PrintHex(codeptr)); - break; } + case OVERFLOW_E: + {sprintf(line, "Overflow at $%s\n", PrintHex(codeptr)); + break;} - case DIVIDE_E: - {sprintf(line, "Divide by zero at $%s\n", PrintHex(codeptr)); - break; } + case DIVIDE_E: + {sprintf(line, "Divide by zero at $%s\n", PrintHex(codeptr)); + break;} } +#if defined (DEBUGGER) + + if (routines > 0) + { + SwitchtoDebugger(); + + if (n==MEMORY_E) DebuggerFatal(D_MEMORY_ERROR); + + RuntimeWarning(line); + debugger_interrupt = true; + debugger_skip = true; + runtime_error = true; + + if (n!=EXPECT_VAL_E) + RecoverLastGood(); + + codeptr = this_codeptr; + + return; + } + + hugo_cleanup_screen(); +#endif + +/* crash dump */ +/* +if (n==UNKNOWN_OP_E || n==ILLEGAL_OP_E || n==EXPECT_VAL_E || n==OVERFLOW_E) +{ + for (n=-8; n<0; n++) + fprintf(stderr, " %c%2X", (n==-8)?'$':' ', MEM(codeptr+n)); + fprintf(stderr, "\n"); + for (n=-8; n<0; n++) + fprintf(stderr, " %3d", MEM(codeptr+n)); + fprintf(stderr, "\n\n> %2X", MEM(codeptr)); + for (n=1; n<8; n++) + fprintf(stderr, " %2X", MEM(codeptr+n)); + fprintf(stderr, "\n"); + fprintf(stderr, ">%3d", MEM(codeptr)); + for (n=1; n<8; n++) + fprintf(stderr, " %3d", MEM(codeptr+n)); + fprintf(stderr, "\n"); +} +*/ sprintf(fatalerrorline, "\nFatal Error: %s", line); - error(fatalerrorline); + PRINTFATALERROR(fatalerrorline); + + hugo_closefiles(); + hugo_blockfree(mem); + mem = NULL; + error("Error code: %d", (int)n); } void Hugo::FileIO() { - char fileiopath[MAXPATH]; - char iotype; - unsigned int fnameval; - long skipaddr; - int i, temp_stack_depth = stack_depth; - - iotype = MEM(codeptr++); - skipaddr = (long)PeekWord(codeptr)*address_scale; - codeptr += 2; - fnameval = GetValue(); - if (game_version >= 23) codeptr++; /* eol */ - - ioerror = 0; - - /* Make sure the filename is legal, 8 alphanumeric characters or less */ - strcpy(line, GetWord(fnameval)); - if (strlen(line) > 8) goto LeaveFileIO; - for (i = 0; i<(int)strlen(line); i++) +#ifndef GLK + char drive[MAXDRIVE], dir[MAXDIR], fname[MAXFILENAME], ext[MAXEXT]; +#endif + char fileiopath[MAXPATH]; + char iotype; + unsigned int fnameval; + long skipaddr; + int i, temp_stack_depth = stack_depth; +#if defined (DEBUGGER) + int tempdbnest; +#endif + + iotype = MEM(codeptr++); + skipaddr = (long)PeekWord(codeptr)*address_scale; + codeptr+=2; + fnameval = GetValue(); + if (game_version>=23) codeptr++; /* eol */ + + ioerror = 0; + + /* Make sure the filename is legal, 8 alphanumeric characters or less */ + strcpy(line, GetWord(fnameval)); + if (strlen(line) > 8) goto LeaveFileIO; + for (i=0; i<(int)strlen(line); i++) + { + if ((line[i]>='0' && line[i]<='9') || (line[i]>='A' && line[i]<='Z') || + (line[i]>='a' && line[i]<='z')) { - if ((line[i] >= '0' && line[i] <= '9') || (line[i] >= 'A' && line[i] <= 'Z') || - (line[i] >= 'a' && line[i] <= 'z')) - { - continue; - } - else - goto LeaveFileIO; + continue; } + else + goto LeaveFileIO; + } - if (ioblock) goto LeaveFileIO; /* can't nest file operations */ - - strcpy(fileiopath, GetWord(fnameval)); + if (ioblock) goto LeaveFileIO; /* can't nest file operations */ - if (iotype == WRITEFILE_T) /* "writefile" */ - { - /* Glk implementation */ - frefid_t fref = nullptr; - - fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode, - fileiopath, 0); - io = glk_stream_open_file(fref, filemode_Write, 0); - glk_fileref_destroy(fref); - if (io == nullptr) goto LeaveFileIO; +#if !defined (GLK) + hugo_splitpath(program_path, drive, dir, fname, ext); + hugo_makepath(fileiopath, drive, dir, GetWord(fnameval), ""); +#else + strcpy(fileiopath, GetWord(fnameval)); +#endif - ioblock = 1; - } - else /* "readfile" */ - { - /* Glk implementation */ - frefid_t fref = nullptr; + if (iotype==WRITEFILE_T) /* "writefile" */ + { +#if !defined (GLK) + /* stdio implementation */ + if ((io = HUGO_FOPEN(fileiopath, "wb"))==NULL) goto LeaveFileIO; +#else + /* Glk implementation */ + frefid_t fref = NULL; + + fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode, + fileiopath, 0); + io = glk_stream_open_file(fref, filemode_Write, 0); + glk_fileref_destroy(fref); + if (io==NULL) goto LeaveFileIO; +#endif + ioblock = 1; + } + else /* "readfile" */ + { +#if !defined (GLK) + /* stdio implementation */ + if ((io = HUGO_FOPEN(fileiopath, "rb"))==NULL) goto LeaveFileIO; +#else + /* Glk implementation */ + frefid_t fref = NULL; + + fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode, + fileiopath, 0); + io = glk_stream_open_file(fref, filemode_Read, 0); + glk_fileref_destroy(fref); + if (io==NULL) goto LeaveFileIO; +#endif + ioblock = 2; + } - fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode, - fileiopath, 0); - if (glk_fileref_does_file_exist(fref)) - io = glk_stream_open_file(fref, filemode_Read, 0); - else - io = nullptr; - glk_fileref_destroy(fref); - if (io == nullptr) goto LeaveFileIO; +#if defined (DEBUGGER) + tempdbnest = dbnest++; +#endif - ioblock = 2; - } + SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0); - SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0); + RunRoutine(codeptr); - RunRoutine(codeptr); +#if defined (DEBUGGER) + dbnest = tempdbnest; +#endif - stack_depth = temp_stack_depth; + stack_depth = temp_stack_depth; - if (ioerror) retflag = 0; + if (ioerror) retflag = 0; - delete io; - io = nullptr; - ioblock = 0; + hugo_fclose(io); + io = NULL; + ioblock = 0; - LeaveFileIO: - ioerror = 0; - codeptr = skipaddr; - } +LeaveFileIO: + ioerror = 0; + codeptr = skipaddr; +} void Hugo::Flushpbuffer() { - if (pbuffer[0] == '\0') return; + if (pbuffer[0]=='\0') return; #ifdef USE_TEXTBUFFER - /* For (single) characters left over from AP(), when Flushpbuffer() gets - called, say, from RunWindow() - */ - if (bufferbreaklen && pbuffer + bufferbreaklen && !(currentfont&PROP_FONT)) - { - TB_AddWord(pbuffer + bufferbreak, - current_text_x + bufferbreaklen, - current_text_y, - current_text_x + bufferbreaklen + FIXEDCHARWIDTH, - current_text_y + lineheight - 1); - } + /* For (single) characters left over from AP(), when Flushpbuffer() gets + called, say, from RunWindow() + */ + if (bufferbreaklen && pbuffer+bufferbreaklen && !(currentfont&PROP_FONT)) + { + TB_AddWord(pbuffer+bufferbreak, + current_text_x+bufferbreaklen, + current_text_y, + current_text_x+bufferbreaklen+FIXEDCHARWIDTH, + current_text_y+lineheight-1); + } #endif - pbuffer[strlen(pbuffer) + 1] = '\0'; - pbuffer[strlen(pbuffer)] = (char)NO_NEWLINE; - Printout(Ltrim(pbuffer)); - currentpos = hugo_textwidth(pbuffer); /* -charwidth; */ - strcpy(pbuffer, ""); - } + pbuffer[strlen(pbuffer)+1] = '\0'; + pbuffer[strlen(pbuffer)] = (char)NO_NEWLINE; + Printout(Ltrim(pbuffer), 0); + currentpos = hugo_textwidth(pbuffer); /* -charwidth; */ + strcpy(pbuffer, ""); +} void Hugo::GetCommand() { - char a[256]; + char a[256]; #ifdef USE_TEXTBUFFER - int start, width, i, y; + int start, width, i, y; #endif - Flushpbuffer(); - AP(""); + Flushpbuffer(); + AP(""); - hugo_settextcolor(fcolor); - hugo_setbackcolor(bgcolor); - if (icolor == -1) - icolor = fcolor; /* check unset input color */ + hugo_settextcolor(fcolor); + hugo_setbackcolor(bgcolor); + if (icolor==-1) + icolor = fcolor; /* check unset input color */ - strncpy(a, GetWord(var[prompt]), 255); - during_player_input = true; - full = 0; + strncpy(a, GetWord(var[prompt]), 255); + during_player_input = true; + full = 0; #ifdef USE_TEXTBUFFER - /* Add the prompt to the textbuffer (using TB_Add()) */ - y = current_text_y; - width = hugo_textwidth(GetWord(var[prompt])); - TB_AddWord(GetWord(var[prompt]), physical_windowleft, y, - physical_windowleft + width, y + lineheight - 1); - - hugo_getline(a); - - /* If hugo_scrollwindowup() called by hugo_getline() shifted things */ - if (current_text_y > y) - { - y += (current_text_y - y); - } + /* Add the prompt to the textbuffer (using TB_Add()) */ + y = current_text_y; + width = hugo_textwidth(GetWord(var[prompt])); + TB_AddWord(GetWord(var[prompt]), physical_windowleft, y, + physical_windowleft+width, y+lineheight-1); + + hugo_getline(a); + + /* If hugo_scrollwindowup() called by hugo_getline() shifted things */ + if (current_text_y > y) + { + y += (current_text_y - y); + } - /* Add each word in the input buffer */ - start = 0; - for (i = 0; i<(int)strlen(buffer); i++) + /* Add each word in the input buffer */ + start = 0; + for (i=0; i<(int)strlen(buffer); i++) + { + if (buffer[i]==' ') { - if (buffer[i] == ' ') - { - buffer[i] = '\0'; - TB_AddWord(buffer + start, physical_windowleft + width, y - lineheight, - physical_windowleft + width + hugo_textwidth(buffer + start), y - 1); - width += hugo_textwidth(buffer + start) + hugo_textwidth(" "); - start = i + 1; - buffer[i] = ' '; - } + buffer[i] = '\0'; + TB_AddWord(buffer+start, physical_windowleft+width, y-lineheight, + physical_windowleft+width+hugo_textwidth(buffer+start), y-1); + width += hugo_textwidth(buffer+start) + hugo_textwidth(" "); + start = i+1; + buffer[i] = ' '; } - /* Add the final word */ - TB_AddWord(buffer + start, physical_windowleft + width, y - lineheight, - physical_windowleft + width + hugo_textwidth(buffer + start), y - 1); + } + /* Add the final word */ + TB_AddWord(buffer+start, physical_windowleft+width, y-lineheight, + physical_windowleft+width+hugo_textwidth(buffer+start), y-1); #else - hugo_getline(a); + hugo_getline(a); #endif - during_player_input = false; - strcpy(buffer, Rtrim(buffer)); + during_player_input = false; + strcpy(buffer, Rtrim(buffer)); - strcpy(parseerr, ""); + strcpy(parseerr, ""); - full = 1; - remaining = 0; - } + full = 1; + remaining = 0; +} char *Hugo::GetString(long addr) { static char a[256]; @@ -848,9 +932,9 @@ char *Hugo::GetString(long addr) { length = Peek(addr); - for (i = 1; i <= length; i++) - a[i - 1] = (char)(Peek(addr + i) - CHAR_TRANSLATION); - a[i - 1] = '\0'; + for (i=1; i<=length; i++) + a[i-1] = (char)(Peek(addr + i) - CHAR_TRANSLATION); + a[i-1] = '\0'; return a; } @@ -861,13 +945,13 @@ char *Hugo::GetText(long textaddr) { int tdatal, tdatah, tlen; /* low byte, high byte, length */ - /* Read the string from memory... */ + /* Read the string from memory... */ if (loaded_in_memory) { - tlen = MEM(codeend + textaddr) + MEM(codeend + textaddr + 1) * 256; - for (i = 0; i<tlen; i++) + tlen = MEM(codeend+textaddr) + MEM(codeend+textaddr+1)*256; + for (i=0; i<tlen; i++) { - g[i] = (char)(MEM(codeend + textaddr + 2 + i) - CHAR_TRANSLATION); + g[i] = (char)(MEM(codeend+textaddr+2+i) - CHAR_TRANSLATION); } g[i] = '\0'; @@ -875,17 +959,17 @@ char *Hugo::GetText(long textaddr) { } /* ...Or load the string from disk */ - if (game->seek(codeend + textaddr)) FatalError(READ_E); + if (hugo_fseek(game, codeend+textaddr, SEEK_SET)) FatalError(READ_E); - tdatal = game->readByte(); - tdatah = game->readByte(); - if (tdatal == EOF || tdatah == EOF || game->err()) FatalError(READ_E); + tdatal = hugo_fgetc(game); + tdatah = hugo_fgetc(game); + if (tdatal==EOF || tdatah==EOF || hugo_ferror(game)) FatalError(READ_E); tlen = tdatal + tdatah * 256; - for (i = 0; i<tlen; i++) + for (i=0; i<tlen; i++) { - if ((a = game->readByte()) == EOF) FatalError(READ_E); + if ((a = hugo_fgetc(game))==EOF) FatalError(READ_E); g[i] = (char)(a - CHAR_TRANSLATION); } g[i] = '\0'; @@ -899,13 +983,13 @@ char *Hugo::GetWord(unsigned int w) { a = w; - if (a == 0) return ""; + if (a==0) return ""; - if (a == PARSE_STRING_VAL) return parseerr; - if (a == SERIAL_STRING_VAL) return serial; + if (a==PARSE_STRING_VAL) return parseerr; + if (a==SERIAL_STRING_VAL) return serial; /* bounds-checking to avoid some sort of memory arena error */ - if ((long)(a + dicttable * 16L) > codeend) + if ((long)(a+dicttable*16L) > codeend) { b = ""; return b; @@ -922,7 +1006,7 @@ void Hugo::HandleTailRecursion(long addr) { codeptr = addr; /* Set up proper default return value for property or routine */ - if (tail_recursion == TAIL_RECURSION_PROPERTY) + if (tail_recursion==TAIL_RECURSION_PROPERTY) ret = 1; else ret = 0; @@ -930,19 +1014,19 @@ void Hugo::HandleTailRecursion(long addr) { /* Unstack until we get to any routine call that got us here */ while (stack_depth) { - if (code_block[stack_depth].type == RUNROUTINE_BLOCK) + if (code_block[stack_depth].type==RUNROUTINE_BLOCK) break; stack_depth--; } #ifdef DEBUGGER - currentroutine = (unsigned int)(codeptr / address_scale); - call[window[VIEW_CALLS].count - 1].addr = currentroutine; - call[window[VIEW_CALLS].count - 1].param = true; + currentroutine = (unsigned int)(codeptr/address_scale); + call[window[VIEW_CALLS].count-1].addr = currentroutine; + call[window[VIEW_CALLS].count-1].param = true; sprintf(debug_line, "Calling: %s", RoutineName(currentroutine)); /* Don't duplicate blank separator line in code window */ - if (codeline[window[CODE_WINDOW].count - 1][0] != 0) + if (codeline[window[CODE_WINDOW].count-1][0] != 0) AddStringtoCodeWindow(""); AddStringtoCodeWindow(debug_line); @@ -966,27 +1050,27 @@ void Hugo::InitGame() { context_commands = 0; #endif game_reset = false; - + SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0); /* Figure out which objects have either a noun or an adjective property; - store it in obj_parselist, one bit per object */ - if ((!obj_parselist) && (obj_parselist = (char *)hugo_blockalloc(sizeof(char)*((objects + 7) / 8)))) + store it in obj_parselist, one bit per object */ + if ((!obj_parselist) && (obj_parselist = (char *)hugo_blockalloc(sizeof(char)*((objects+7)/8)))) { - - for (i = 0; i<objects; i++) + + for (i=0; i<objects; i++) { - if (i % 8 == 0) obj_parselist[i / 8] = 0; - + if (i%8==0) obj_parselist[i/8] = 0; + if (PropAddr(i, adjective, 0) || PropAddr(i, noun, 0)) - obj_parselist[i / 8] |= 1 << (i % 8); + obj_parselist[i/8] |= 1 << (i%8); else - obj_parselist[i / 8] &= ~(1 << (i % 8)); + obj_parselist[i/8] &= ~(1 << (i%8)); } } - + #if defined (DEBUGGER) - for (i = 0; i<MAXLOCALS; i++) strcpy(localname[i], ""); + for (i=0; i<MAXLOCALS; i++) strcpy(localname[i], ""); window[VIEW_LOCALS].count = current_locals = 0; PassLocals(0); @@ -1010,85 +1094,135 @@ void Hugo::LoadGame() { #ifndef LOADGAMEDATA_REPLACED long c; #endif - game = &_gameFile; - filelength = game->size(); - game->seek(0); - if (game->err()) FatalError(READ_E); - if ((game_version = game->readByte()) == EOF) FatalError(OPEN_E); +#if defined (DEBUGGER) + if (!strcmp(gamefile, "")) + { + game = NULL; + strcpy(gamefile, "(no file)"); + return; + } +#endif + +#if !defined (GLK) /* since in Glk the game stream is always open */ + if ((game = TrytoOpen(gamefile, "rb", "games"))==NULL) + { + if ((game = TrytoOpen(gamefile, "rb", "object"))==NULL) + FatalError(OPEN_E); + } +#endif + + hugo_fseek(game, 0, SEEK_END); + filelength = hugo_ftell(game); + hugo_fseek(game, 0, SEEK_SET); + + if (hugo_ferror(game)) FatalError(READ_E); + if ((game_version = hugo_fgetc(game))==EOF) FatalError(OPEN_E); /* Earlier versions of the compiler wrote the version code as - 1 or 2 instead of 10 or 20. + 1 or 2 instead of 10 or 20. */ - if (game_version == 1 || game_version == 2) - game_version *= 10; + if (game_version==1 || game_version==2) + game_version*=10; if (game_version < 21) object_size = 12; if (game_version < 31) address_scale = 4; - check_version = HEVERSION * 10 + HEREVISION; + check_version = HEVERSION*10 + HEREVISION; +#if defined (COMPILE_V25) + if (check_version==25 && (game_version>=30 && game_version<=39)) + check_version = game_version; +#endif defseg = gameseg; if (game_version < HEVERSION) { +#if defined (DEBUGGER) + hugo_cleanup_screen(); + hugo_clearfullscreen(); +#endif sprintf(line, "Hugo Compiler v%d.%d or later required.\n", HEVERSION, HEREVISION); if (game_version>0) - sprintf(line + strlen(line), "File \"%s\" is v%d.%d.\n", gamefile, game_version / 10, game_version % 10); + sprintf(line+strlen(line), "File \"%s\" is v%d.%d.\n", gamefile, game_version/10, game_version%10); - error(line); +#if defined (DEBUGGER_PRINTFATALERROR) + DEBUGGER_PRINTFATALERROR(line); +#else + //debug("%s", line); +#endif + hugo_closefiles(); + hugo_blockfree(mem); + mem = NULL; + + hugo_exit(line); } else if (game_version > check_version) { - error("File \"%s\" is incorrect or unknown version.\n", gamefile); +#if defined (DEBUGGER) + hugo_cleanup_screen(); + hugo_clearfullscreen(); +#endif + sprintf(line, "File \"%s\" is incorrect or unknown version.\n", gamefile); + +#if defined (DEBUGGER_PRINTFATALERROR) + DEBUGGER_PRINTFATALERROR(line); +#else + //debug("%s", line); +#endif + hugo_closefiles(); + hugo_blockfree(mem); + mem = NULL; + hugo_exit(line); /* ditto */ } - hugo_settextpos(1, physical_windowheight / lineheight); + hugo_settextpos(1, physical_windowheight/lineheight); - if (game_version >= 25) - game->seek(H_TEXTBANK, SEEK_SET); + if (game_version>=25) + hugo_fseek(game, H_TEXTBANK, SEEK_SET); else /* Because pre-v2.5 didn't have performaddr in the header */ - game->seek(H_TEXTBANK - 2L, SEEK_SET); + hugo_fseek(game, H_TEXTBANK-2L, SEEK_SET); - data = game->readByte(); - textbank = game->readByte(); - if (data == EOF || textbank == EOF || game->err()) FatalError(READ_E); - textbank = (textbank * 256L + (long)data) * 16L; + data = hugo_fgetc(game); + textbank = hugo_fgetc(game); + if (data==EOF || textbank==EOF || hugo_ferror(game)) FatalError(READ_E); + textbank = (textbank*256L + (long)data) * 16L; codeend = textbank; /* Use a 1024-byte read block */ ccount = 1024; - if (game->seek(0, SEEK_SET)) FatalError(READ_E); + if (hugo_fseek(game, 0, SEEK_SET)) FatalError(READ_E); #ifndef LOADGAMEDATA_REPLACED /* Allocate as much memory as is required */ - if ((!loaded_in_memory) || (mem = (unsigned char *)hugo_blockalloc(filelength)) == nullptr) + if ((!loaded_in_memory) || (mem = (unsigned char *)hugo_blockalloc(filelength))==NULL) { loaded_in_memory = 0; - if ((mem = (unsigned char *)hugo_blockalloc(codeend)) == nullptr) + if ((mem = (unsigned char *)hugo_blockalloc(codeend))==NULL) FatalError(MEMORY_E); } c = 0; /* Load either the entire file or just up to the start of the - text bank + text bank */ - while (c < (loaded_in_memory ? filelength : codeend)) + while (c < (loaded_in_memory ? filelength:codeend)) { /* Complicated, but basically just makes sure that - the last read (whether loaded_in_memory or not) - doesn't override the end of the file. Shouldn't - normally be a problem for fread(), but it caused - a crash under MSVC++. + the last read (whether loaded_in_memory or not) + doesn't override the end of the file. Shouldn't + normally be a problem for fread(), but it caused + a crash under MSVC++. */ - i = game->read((unsigned char *)&mem[c], - (loaded_in_memory) ? - ((filelength - c>(long)ccount) ? ccount : (size_t)(filelength - c)) : - ((codeend - c>(long)ccount) ? ccount : (size_t)(codeend - c))); + i = hugo_fread((unsigned char *)&mem[c], sizeof(unsigned char), + (loaded_in_memory)? + ((filelength-c>(long)ccount)?ccount:(size_t)(filelength-c)): + ((codeend-c>(long)ccount)?ccount:(size_t)(codeend-c)), + game); if (!i) break; c += i; @@ -1097,36 +1231,36 @@ void Hugo::LoadGame() { if (!LoadGameData(false)) FatalError(READ_E); #endif - if (game->err()) FatalError(READ_E); + if (hugo_ferror(game)) FatalError(READ_E); defseg = gameseg; /* Read header: */ id[0] = Peek(H_ID); - id[1] = Peek(H_ID + 1); + id[1] = Peek(H_ID+1); id[2] = '\0'; - for (i = 0; i<8; i++) - serial[i] = Peek(H_SERIAL + i); + for (i=0; i<8; i++) + serial[i] = Peek(H_SERIAL+i); serial[8] = '\0'; - codestart = PeekWord(H_CODESTART); - objtable = PeekWord(H_OBJTABLE) + gameseg; - proptable = PeekWord(H_PROPTABLE) + gameseg; + codestart = PeekWord(H_CODESTART); + objtable = PeekWord(H_OBJTABLE) + gameseg; + proptable = PeekWord(H_PROPTABLE) + gameseg; eventtable = PeekWord(H_EVENTTABLE) + gameseg; arraytable = PeekWord(H_ARRAYTABLE) + gameseg; - dicttable = PeekWord(H_DICTTABLE) + gameseg; - syntable = PeekWord(H_SYNTABLE) + gameseg; + dicttable = PeekWord(H_DICTTABLE) + gameseg; + syntable = PeekWord(H_SYNTABLE) + gameseg; - initaddr = PeekWord(H_INIT); - mainaddr = PeekWord(H_MAIN); - parseaddr = PeekWord(H_PARSE); + initaddr = PeekWord(H_INIT); + mainaddr = PeekWord(H_MAIN); + parseaddr = PeekWord(H_PARSE); parseerroraddr = PeekWord(H_PARSEERROR); findobjectaddr = PeekWord(H_FINDOBJECT); - endgameaddr = PeekWord(H_ENDGAME); - speaktoaddr = PeekWord(H_SPEAKTO); - performaddr = PeekWord(H_PERFORM); + endgameaddr = PeekWord(H_ENDGAME); + speaktoaddr = PeekWord(H_SPEAKTO); + performaddr = PeekWord(H_PERFORM); /* Read totals: */ @@ -1151,43 +1285,163 @@ void Hugo::LoadGame() { { data = FindWord("(display)"); - for (i = 0; i<objects; i++) + for (i=0; i<objects; i++) { - if (GetProp(i, 0, 1, true) == data) + if (GetProp(i, 0, 1, true)==data) { display_object = i; break; } } } - + /* build punctuation string (additional user-specified punctuation) */ synptr = 2; strcpy(punc_string, ""); - for (i = 1; i <= syncount; i++) + for (i=1; i<=syncount; i++) { defseg = syntable; - if (Peek(synptr) == 3) /* 3 = punctuation */ + if (Peek(synptr)==3) /* 3 = punctuation */ { - strcpy(line, GetWord(PeekWord(synptr + 1))); + strcpy(line, GetWord(PeekWord(synptr+1))); if (strlen(line) + strlen(punc_string) > 63) break; strcat(punc_string, line); } - synptr += 5; + synptr+=5; + } +} + +#if !defined (GLK) /* ParseCommandLine() is omitted for Glk */ + +signed char def_fcolor = DEF_FCOLOR; +signed char def_bgcolor = DEF_BGCOLOR; +signed char def_slfcolor = DEF_SLFCOLOR; +signed char def_slbgcolor = DEF_SLBGCOLOR; + +void ParseCommandLine(int argc, char *argv[]) +{ + char drive[MAXDRIVE], dir[MAXDIR], fname[MAXFILENAME], ext[MAXEXT]; + char* game_file_arg = NULL; + +#if defined(GCC_UNIX) && defined(DO_COLOR) + int ch; + /* Parse comand line options (colour switches) */ + while ((ch = getopt(argc, argv, "f:b:F:B:?h")) != -1) { + switch (ch) { + case 'f': + def_fcolor = atoi(optarg); + break; + case 'b': + def_bgcolor = atoi(optarg); + break; + case 'F': + def_slfcolor = atoi(optarg); + break; + case 'B': + def_slbgcolor = atoi(optarg); + break; + case 'h': + case '?': + default: + Banner(); + if (mem) hugo_blockfree(mem); + mem = NULL; + exit(0); + } + } + if ( optind < argc ) { + game_file_arg = argv[optind]; + } +#else + if (argc>1) { + game_file_arg = argv[1]; } +#endif + + if (game_file_arg==NULL) + { + Banner(); + if (mem) hugo_blockfree(mem); + mem = NULL; + exit(0); + } + + hugo_splitpath(game_file_arg, drive, dir, fname, ext); + + if (strcmp(ext, "")) + strcpy(gamefile, game_file_arg); + else + hugo_makepath(gamefile, drive, dir, fname, +#if defined (DEBUGGER) + "hdx"); +#else + "hex"); +#endif + + if (getenv("HUGO_SAVE")) + hugo_makepath(savefile, "", getenv("HUGO_SAVE"), fname, "sav"); + else + hugo_makepath(savefile, drive, dir, fname, "sav"); + + if (getenv("HUGO_RECORD")) + hugo_makepath(recordfile, "", getenv("HUGO_RECORD"), fname, "rec"); + else + hugo_makepath(recordfile, drive, dir, fname, "rec"); + + strcpy(scriptfile, DEF_PRN); + + hugo_makepath(gamepath, drive, dir, "", ""); } +#endif /* GLK */ + void Hugo::PassLocals(int n) { int i; - for (i = 0; i<MAXLOCALS; i++) + for (i=0; i<MAXLOCALS; i++) { - var[MAXGLOBALS + i] = passlocal[i]; + var[MAXGLOBALS+i] = passlocal[i]; passlocal[i] = 0; } arguments_passed = n; } +#ifdef NO_INLINE_MEM_FUNCTIONS + +/* PEEK */ + +unsigned char Peek(long a) +{ + return MEM(defseg * 16L + a); +} + + +/* PEEKWORD */ + +unsigned int PeekWord(long a) +{ + return (unsigned char)MEM(defseg*16L+a) + (unsigned char)MEM(defseg*16L+a+1)*256; +} + + +/* POKE */ + +void Poke(unsigned int a, unsigned char v) +{ + SETMEM(defseg * 16L + a, v); +} + + +/* POKEWORD */ + +void PokeWord(unsigned int a, unsigned int v) +{ + SETMEM(defseg * 16L + a, (char)(v%256)); + SETMEM(defseg * 16L + a + 1, (char)(v/256)); +} + +#endif /* NO_INLINED_MEM_FUNCTIONS */ + const char *Hugo::PrintHex(long a) { static char hex[7]; int h = 0; @@ -1202,12 +1456,12 @@ const char *Hugo::PrintHex(long a) { if (a < 256L) hex[h++] = '0'; if (a < 16L) hex[h++] = '0'; - sprintf(hex + h, "%lX", a); + sprintf(hex+h, "%lX", a); return hex; } -void Hugo::Printout(char *a) { +void Hugo::Printout(char *a, int no_scrollback_linebreak) { char b[2], sticky = 0, trimmed = 0; char tempfcolor; int i, l; @@ -1217,20 +1471,20 @@ void Hugo::Printout(char *a) { /* hugo_font() should do this if necessary, but just in case */ if (lineheight < FIXEDLINEHEIGHT) lineheight = FIXEDLINEHEIGHT; - + tempfcolor = fcolor; /* The before-check of the linecount: */ if (full) { /* -1 here since it's before printing */ - if (full >= physical_windowheight / lineheight - 1) + if (full >= physical_windowheight/lineheight-1) PromptMore(); } - if ((a[0] != '\0') && a[strlen(a) - 1] == (char)NO_NEWLINE) + if ((a[0]!='\0') && a[strlen(a)-1]==(char)NO_NEWLINE) { - a[strlen(a) - 1] = '\0'; + a[strlen(a)-1] = '\0'; sticky = true; } @@ -1238,19 +1492,19 @@ void Hugo::Printout(char *a) { /* The easy part is just skimming <a> and processing each code - or printed character, as the case may be: + or printed character, as the case may be: */ - + l = 0; /* physical length of string */ - for (i = 0; i<(int)strlen(a); i++) + for (i=0; i<(int)strlen(a); i++) { - if ((a[i] == ' ') && !trimmed && currentpos == 0) + if ((a[i]==' ') && !trimmed && currentpos==0) { continue; } - if ((unsigned char)a[i] > ' ' || a[i] == FORCED_SPACE) + if ((unsigned char)a[i] > ' ' || a[i]==FORCED_SPACE) { trimmed = true; last_printed_font = currentfont; @@ -1258,55 +1512,55 @@ void Hugo::Printout(char *a) { switch (b[0] = a[i]) { - case FONT_CHANGE: - n = (int)(a[++i] - 1); - if (currentfont != n) - hugo_font(currentfont = n); - break; + case FONT_CHANGE: + n = (int)(a[++i]-1); + if (currentfont != n) + hugo_font(currentfont = n); + break; - case COLOR_CHANGE: - fcolor = (char)(a[++i] - 1); - hugo_settextcolor((int)fcolor); - hugo_setbackcolor((int)(a[++i] - 1)); - hugo_font(currentfont); - break; + case COLOR_CHANGE: + fcolor = (char)(a[++i]-1); + hugo_settextcolor((int)fcolor); + hugo_setbackcolor((int)(a[++i]-1)); + hugo_font(currentfont); + break; - default: - if (b[0] == FORCED_SPACE) b[0] = ' '; - l += hugo_charwidth(b[0]); + default: + if (b[0]==FORCED_SPACE) b[0] = ' '; + l += hugo_charwidth(b[0]); - /* A minor adjustment for font changes and RunWindow() to make - sure we're not printing unnecessarily downscreen - */ - if ((just_left_window) && current_text_y > physical_windowbottom - lineheight) - { - current_text_y = physical_windowbottom - lineheight; - } - just_left_window = false; + /* A minor adjustment for font changes and RunWindow() to make + sure we're not printing unnecessarily downscreen + */ + if ((just_left_window) && current_text_y > physical_windowbottom-lineheight) + { + current_text_y = physical_windowbottom-lineheight; + } + just_left_window = false; - hugo_print(b); + hugo_print(b); } - if (script && (unsigned char)b[0] >= ' ') - script->putBuffer(b, strlen(b)); + if (script && (unsigned char)b[0]>=' ') + if (hugo_writetoscript(b) < 0) FatalError(WRITE_E); #if defined (SCROLLBACK_DEFINED) - if (!inwindow && (unsigned char)b[0] >= ' ') + if (!inwindow && (unsigned char)b[0]>=' ') { #ifdef USE_SMARTFORMATTING /* Undo smart-formatting for ASCII scrollback */ switch ((unsigned char)b[0]) { - case 151: - hugo_sendtoscrollback("--"); - continue; - case 145: - case 146: - b[0] = '\''; - break; - case 147: - case 148: - b[0] = '\"'; + case 151: + hugo_sendtoscrollback("--"); + continue; + case 145: + case 146: + b[0] = '\''; + break; + case 147: + case 148: + b[0] = '\"'; } #endif hugo_sendtoscrollback(b); @@ -1315,37 +1569,37 @@ void Hugo::Printout(char *a) { } /* If we've got a linefeed and didn't hit the right edge of the - window + window */ #ifdef NO_TERMINAL_LINEFEED if (!sticky) #else - if (!sticky && currentpos + l < physical_windowwidth) + if (!sticky && currentpos+l < physical_windowwidth) #endif { /* The background color may have to be temporarily set if we're - not in a window--the reason is that full lines of the - current background color might be printed by the OS-specific - scrolling function. (This behavior is overridden by the - Hugo Engine for in-window printing, which always adds new - lines in the current background color when scrolling.) + not in a window--the reason is that full lines of the + current background color might be printed by the OS-specific + scrolling function. (This behavior is overridden by the + Hugo Engine for in-window printing, which always adds new + lines in the current background color when scrolling.) */ - hugo_setbackcolor((inwindow) ? bgcolor : default_bgcolor); + hugo_setbackcolor((inwindow)?bgcolor:default_bgcolor); hugo_print("\r"); i = currentfont; hugo_font(currentfont = last_printed_font); #ifndef GLK - if (currentline > physical_windowheight / lineheight) + if (currentline > physical_windowheight/lineheight) { - int full_limit = physical_windowheight / lineheight; + int full_limit = physical_windowheight/lineheight; hugo_scrollwindowup(); if ((current_text_y) - && full >= full_limit - 3 - && physical_windowbottom - current_text_y - lineheight > lineheight / 2) + && full >= full_limit-3 + && physical_windowbottom-current_text_y-lineheight > lineheight/2) { PromptMore(); } @@ -1353,7 +1607,7 @@ void Hugo::Printout(char *a) { } /* Don't scroll single-line windows before PromptMore() */ - else if (physical_windowheight / lineheight > 1) + else if (physical_windowheight/lineheight > 1) #endif { hugo_print("\n"); @@ -1379,96 +1633,230 @@ void Hugo::Printout(char *a) { } /* Otherwise, take care of all the line-feeding, line-counting, - etc. + etc. */ else { currentpos = 0; - if (currentline++ > physical_windowheight / lineheight) - currentline = physical_windowheight / lineheight; + if (currentline++ > physical_windowheight/lineheight) + currentline = physical_windowheight/lineheight; if (!playback) skipping_more = false; ++full; - + /* The after-check of the linecount: */ - if ((full) && full >= physical_windowheight / lineheight) + if ((full) && full >= physical_windowheight/lineheight) { PromptMore(); } - if (script) + if (script && !no_scrollback_linebreak) { - script->putBuffer("\n", 1); + if (hugo_writetoscript("\n")<0) FatalError(WRITE_E); } #if defined (SCROLLBACK_DEFINED) - if (!inwindow) hugo_sendtoscrollback("\n"); + if (!inwindow && !no_scrollback_linebreak) hugo_sendtoscrollback("\n"); #endif } fcolor = tempfcolor; } -int Hugo::RecordCommands() { - remaining = 0; +#ifndef PROMPTMORE_REPLACED + +void Hugo::PromptMore() { + char temp_during_player_input; + int k, tempcurrentfont; + int temp_current_text_y = current_text_y; + + if (playback && skipping_more) + { + full = 0; + return; + } skipping_more = false; + + /* Clear the key buffer */ + while (hugo_iskeywaiting()) hugo_getkey(); - switch (Peek(codeptr)) + temp_during_player_input = during_player_input; + during_player_input = false; + + tempcurrentfont = currentfont; + hugo_font(currentfont = NORMAL_FONT); + + hugo_settextpos(1, physical_windowheight/lineheight); + +#ifdef NO_TERMINAL_LINEFEED + /* For ports where it's possible, do a better "MORE..." prompt + without a flashing caret */ + if (default_bgcolor!=DEF_SLBGCOLOR) { - case RECORDON_T: + /* system statusline colors */ + hugo_settextcolor(DEF_SLFCOLOR); + hugo_setbackcolor(DEF_SLBGCOLOR); + } + else { - if (!record && !playback) - { - /* Glk implementation */ - frefid_t fref = nullptr; + /* system colors */ + if (DEF_FCOLOR < 8) + hugo_settextcolor(DEF_FCOLOR+8); /* bright */ + else + hugo_settextcolor(DEF_FCOLOR); + hugo_setbackcolor(DEF_BGCOLOR); + } - fref = glk_fileref_create_by_prompt(fileusage_Transcript | fileusage_TextMode, - filemode_Write, 0); - record = glk_stream_open_file(fref, filemode_Write, 0); - glk_fileref_destroy(fref); - if (!record) - return 0; + if (current_text_y) + current_text_y = physical_windowbottom - lineheight; - return 1; - } - break; + /* Make sure we fit in a window */ + if (physical_windowwidth/FIXEDCHARWIDTH >= 19) + hugo_print(" [MORE...] "); + else + hugo_print("[MORE...]"); + + if (!inwindow) + hugo_setbackcolor(default_bgcolor); + else + hugo_setbackcolor(bgcolor); + + /* Note that hugo_iskeywaiting() must flush the printing buffer, + if one is being employed */ + while (!hugo_iskeywaiting()) + { + hugo_timewait(100); } - case RECORDOFF_T: + k = hugo_waitforkey(); + +#else + /* The normal, with-caret way of doing it */ + /* system colors */ + hugo_settextcolor(16); /* DEF_FCOLOR); */ + hugo_setbackcolor(17); /* DEF_BGCOLOR); */ + hugo_print("[MORE...]"); + + k = hugo_waitforkey(); + + if (!inwindow) + hugo_setbackcolor(default_bgcolor); + else + hugo_setbackcolor(bgcolor); +#endif + + if (playback && k==27) /* if ESC is pressed during playback */ { - if (playback) return 1; + if (hugo_fclose(playback)) + FatalError(READ_E); + playback = NULL; + } + else if (playback && k=='+') + skipping_more = true; + + hugo_settextpos(1, physical_windowheight/lineheight); +#ifdef NO_TERMINAL_LINEFEED + current_text_y = physical_windowbottom - lineheight; + /* Make sure we fit in a window */ + if (physical_windowwidth/FIXEDCHARWIDTH >= 19) + hugo_print(" "); + else + hugo_print(" "); +#else + hugo_print(" "); +#endif + hugo_font(currentfont = tempcurrentfont); - if (record) + hugo_settextpos(1, physical_windowheight/lineheight); + current_text_y = temp_current_text_y; + full = 0; + + hugo_settextcolor(fcolor); + hugo_setbackcolor(bgcolor); + + during_player_input = temp_during_player_input; +} + +#endif /* ifndef PROMPTMORE_REPLACED */ + +int Hugo::RecordCommands() { + remaining = 0; + skipping_more = false; + + switch (Peek(codeptr)) + { + case RECORDON_T: { - delete record; - record = nullptr; - return 1; + if (!record && !playback) + { +#if !defined (GLK) + /* stdio implementation */ + hugo_getfilename("for command recording", recordfile); + if (!strcmp(line, "")) + return 0; + if (!hugo_overwrite(line)) + return 0; + if (!(record = HUGO_FOPEN(line, "wt"))) + return 0; + strcpy(recordfile, line); +#else + /* Glk implementation */ + frefid_t fref = NULL; + + fref = glk_fileref_create_by_prompt(fileusage_Transcript | fileusage_TextMode, + filemode_Write, 0); + record = glk_stream_open_file(fref, filemode_Write, 0); + glk_fileref_destroy(fref); + if (!record) + return 0; +#endif + return 1; + } + break; } - break; - } - case PLAYBACK_T: - { - if (!playback) + case RECORDOFF_T: { - /* Glk implementation */ - frefid_t fref = nullptr; + if (playback) return 1; - fref = glk_fileref_create_by_prompt(fileusage_InputRecord | fileusage_TextMode, - filemode_Read, 0); - if (glk_fileref_does_file_exist(fref)) - playback = glk_stream_open_file(fref, filemode_Read, 0); - else - playback = nullptr; - glk_fileref_destroy(fref); + if (record) + { + if (hugo_fclose(record)) return (0); + + record = NULL; + return 1; + } + break; + } + + case PLAYBACK_T: + { if (!playback) - return 0; + { +#if !defined (GLK) + /* stdio implementation */ + hugo_getfilename("for command playback", recordfile); + if (!strcmp(line, "")) + return 0; + if (!(playback = HUGO_FOPEN(line, "rt"))) + return 0; + strcpy(recordfile, line); +#else + /* Glk implementation */ + frefid_t fref = NULL; - return 1; + fref = glk_fileref_create_by_prompt(fileusage_InputRecord | fileusage_TextMode, + filemode_Read, 0); + playback = glk_stream_open_file(fref, filemode_Read, 0); + glk_fileref_destroy(fref); + if (!playback) + return 0; +#endif + return 1; + } + break; } - break; - } } return 0; } @@ -1485,43 +1873,45 @@ void Hugo::SaveUndo(int a, int b, int c, int d, int e) { undostack[undoptr][4] = e; /* Put zeroes at end of this operation in case - the stack wraps around */ + the stack wraps around */ tempptr = undoptr; - if (++undoptr == MAXUNDO) undoptr = 0; + if (++undoptr==MAXUNDO) undoptr = 0; undostack[undoptr][0] = 0; undostack[undoptr][1] = 0; undoptr = tempptr; - if (++undoturn == MAXUNDO) /* turn too complex */ - { - undoptr = 0; + if (++undoturn==MAXUNDO) /* turn too complex */ + {undoptr = 0; undoturn = MAXUNDO; - undoinvalid = 1; - } + undoinvalid = 1;} - if (++undoptr == MAXUNDO) undoptr = 0; + if (++undoptr==MAXUNDO) undoptr = 0; } } void Hugo::SetStackFrame(int depth, int type, long brk, long returnaddr) { - if (depth == RESET_STACK_DEPTH) stack_depth = 0; - else if (++stack_depth >= MAXSTACKDEPTH) FatalError(MEMORY_E); + if (depth==RESET_STACK_DEPTH) stack_depth = 0; + else if (++stack_depth>=MAXSTACKDEPTH) FatalError(MEMORY_E); code_block[stack_depth].type = type; code_block[stack_depth].brk = brk; code_block[stack_depth].returnaddr = returnaddr; + +#if defined (DEBUGGER) + code_block[stack_depth].dbnest = dbnest; +#endif } void Hugo::SetupDisplay() { hugo_settextmode(); hugo_settextwindow(1, 1, - SCREENWIDTH / FIXEDCHARWIDTH, SCREENHEIGHT / FIXEDLINEHEIGHT); + SCREENWIDTH/FIXEDCHARWIDTH, SCREENHEIGHT/FIXEDLINEHEIGHT); last_window_left = 1; last_window_top = 1; - last_window_right = SCREENWIDTH / FIXEDCHARWIDTH; - last_window_bottom = SCREENHEIGHT / FIXEDLINEHEIGHT; + last_window_right = SCREENWIDTH/FIXEDCHARWIDTH; + last_window_bottom = SCREENHEIGHT/FIXEDLINEHEIGHT; hugo_settextcolor(16); hugo_setbackcolor(17); @@ -1534,225 +1924,272 @@ char Hugo::SpecialChar(const char *a, int *i) { r = a[*i]; s = r; - if (r == '\"') return r; + if (r=='\"') return r; /* For a couple of versions, Hugo allowed Inform-style - punctuation control characters; I don't remember - exactly why. + punctuation control characters; I don't remember + exactly why. */ if (game_version <= 22) - if (r == '~' || r == '^') return r; + if (r=='~' || r=='^') return r; - if (r == '(') - { - r = a[++*i]; - skipbracket = true; - } + if (r=='(') + {r = a[++*i]; + skipbracket = true;} switch (r) { - case '`': /* accent grave */ - { - /* Note that the "s = '...'" characters are - Latin-1 and may not display properly under, - e.g., DOS */ + case '`': /* accent grave */ + { + /* Note that the "s = '...'" characters are + Latin-1 and may not display properly under, + e.g., DOS */ - s = a[++*i]; + s = a[++*i]; #ifndef NO_LATIN1_CHARSET - switch (s) - { - case 'a': s = (char)0xe0; break; /* ? */ - case 'e': s = (char)0xe8; break; /* ? */ - case 'i': s = (char)0xec; break; /* ? */ - case 'o': s = (char)0xf2; break; /* ? */ - case 'u': s = (char)0xf9; break; /* ? */ - case 'A': s = (char)0xc0; break; /* ? */ - case 'E': s = (char)0xc8; break; /* ? */ - case 'I': s = (char)0xcc; break; /* ? */ - case 'O': s = (char)0xd2; break; /* ? */ - case 'U': s = (char)0xd9; break; /* ? */ - } + switch (s) + { + case 'a': s = (char)0xe0; break; + case 'e': s = (char)0xe8; break; + case 'i': s = (char)0xec; break; + case 'o': s = (char)0xf2; break; + case 'u': s = (char)0xf9; break; + case 'A': s = (char)0xc0; break; + case 'E': s = (char)0xc8; break; + case 'I': s = (char)0xcc; break; + case 'O': s = (char)0xd2; break; + case 'U': s = (char)0xd9; break; + } #endif - break; - } - case '\'': /* accent acute */ - { - s = a[++*i]; -#ifndef NO_LATIN1_CHARSET - switch (s) - { - case 'a': s = (char)0xe1; break; /* ? */ - case 'e': s = (char)0xe9; break; /* ? */ - case 'i': s = (char)0xed; break; /* ? */ - case 'o': s = (char)0xf3; break; /* ? */ - case 'u': s = (char)0xfa; break; /* ? */ - case 'y': s = (char)0xfd; break; - case 'A': s = (char)0xc1; break; /* ? */ - case 'E': s = (char)0xc9; break; /* ? */ - case 'I': s = (char)0xcd; break; /* ? */ - case 'O': s = (char)0xd3; break; /* ? */ - case 'U': s = (char)0xda; break; /* ? */ - case 'Y': s = (char)0xdd; break; /* ? */ + break; } -#endif - break; - } - case '~': /* tilde */ - { - s = a[++*i]; -#ifndef NO_LATIN1_CHARSET - switch (s) + case '\'': /* accent acute */ { - case 'a': s = (char)0xe3; break; /* ? */ - case 'n': s = (char)0xf1; break; /* ? */ - case 'o': s = (char)0xf5; break; /* ? */ - case 'A': s = (char)0xc3; break; /* ? */ - case 'N': s = (char)0xd1; break; /* ? */ - case 'O': s = (char)0xd5; break; /* ? */ - } -#endif - break; - } - case '^': /* circumflex */ - { - s = a[++*i]; + s = a[++*i]; #ifndef NO_LATIN1_CHARSET - switch (s) - { - case 'a': s = (char)0xe2; break; /* ? */ - case 'e': s = (char)0xea; break; /* ? */ - case 'i': s = (char)0xee; break; /* ? */ - case 'o': s = (char)0xf4; break; /* ? */ - case 'u': s = (char)0xfb; break; /* ? */ - case 'A': s = (char)0xc2; break; /* ? */ - case 'E': s = (char)0xca; break; /* ? */ - case 'I': s = (char)0xce; break; /* ? */ - case 'O': s = (char)0xd4; break; /* ? */ - case 'U': s = (char)0xdb; break; /* ? */ - } + switch (s) + { + case 'a': s = (char)0xe1; break; + case 'e': s = (char)0xe9; break; + case 'i': s = (char)0xed; break; + case 'o': s = (char)0xf3; break; + case 'u': s = (char)0xfa; break; + case 'y': s = (char)0xfd; break; + case 'A': s = (char)0xc1; break; + case 'E': s = (char)0xc9; break; + case 'I': s = (char)0xcd; break; + case 'O': s = (char)0xd3; break; + case 'U': s = (char)0xda; break; + case 'Y': s = (char)0xdd; break; + } #endif - break; - } - case ':': /* umlaut */ - { - s = a[++*i]; -#ifndef NO_LATIN1_CHARSET - switch (s) - { - case 'a': s = (char)0xe4; break; /* ? */ - case 'e': s = (char)0xeb; break; /* ? */ - case 'i': s = (char)0xef; break; /* ? */ - case 'o': s = (char)0xf6; break; /* ? */ - case 'u': s = (char)0xfc; break; /* ? */ - /* case 'y': s = (char)0xff; break; */ /* ? */ - case 'A': s = (char)0xc4; break; /* ? */ - case 'E': s = (char)0xcb; break; /* ? */ - case 'I': s = (char)0xcf; break; /* ? */ - case 'O': s = (char)0xd6; break; /* ? */ - case 'U': s = (char)0xdc; break; /* ? */ + break; } + case '~': /* tilde */ + { + s = a[++*i]; +#ifndef NO_LATIN1_CHARSET + switch (s) + { + case 'a': s = (char)0xe3; break; + case 'n': s = (char)0xf1; break; + case 'o': s = (char)0xf5; break; + case 'A': s = (char)0xc3; break; + case 'N': s = (char)0xd1; break; + case 'O': s = (char)0xd5; break; + } #endif - break; - } - case ',': /* cedilla */ - { - s = a[++*i]; + break; + } + case '^': /* circumflex */ + { + s = a[++*i]; #ifndef NO_LATIN1_CHARSET - switch (s) + switch (s) + { + case 'a': s = (char)0xe2; break; + case 'e': s = (char)0xea; break; + case 'i': s = (char)0xee; break; + case 'o': s = (char)0xf4; break; + case 'u': s = (char)0xfb; break; + case 'A': s = (char)0xc2; break; + case 'E': s = (char)0xca; break; + case 'I': s = (char)0xce; break; + case 'O': s = (char)0xd4; break; + case 'U': s = (char)0xdb; break; + } +#endif + break; + } + case ':': /* umlaut */ { - case 'C': s = (char)0xc7; break; /* ? */ - case 'c': s = (char)0xe7; break; /* ? */ + s = a[++*i]; +#ifndef NO_LATIN1_CHARSET + switch (s) + { + case 'a': s = (char)0xe4; break; + case 'e': s = (char)0xeb; break; + case 'i': s = (char)0xef; break; + case 'o': s = (char)0xf6; break; + case 'u': s = (char)0xfc; break; + /* case 'y': s = (char)0xff; break; */ + case 'A': s = (char)0xc4; break; + case 'E': s = (char)0xcb; break; + case 'I': s = (char)0xcf; break; + case 'O': s = (char)0xd6; break; + case 'U': s = (char)0xdc; break; + } +#endif + break; } + case ',': /* cedilla */ + { + s = a[++*i]; +#ifndef NO_LATIN1_CHARSET + switch (s) + { + case 'C': s = (char)0xc7; break; + case 'c': s = (char)0xe7; break; + } #endif - break; - } - case '<': /* Spanish left quotation marks */ + break; + } + case '<': /* Spanish left quotation marks */ #ifndef NO_LATIN1_CHARSET - s = (char)0xab; /* ? */ + s = (char)0xab; #endif - break; - case '>': /* Spanish right quotation marks */ + break; + case '>': /* Spanish right quotation marks */ #ifndef NO_LATIN1_CHARSET - s = (char)0xbb; /* ? */ - break; + s = (char)0xbb; + break; #endif - case '!': /* upside-down exclamation mark */ + case '!': /* upside-down exclamation mark */ #ifndef NO_LATIN1_CHARSET - s = (char)0xa1; /* ? */ + s = (char)0xa1; #endif - break; - case '?': /* upside-down question mark */ + break; + case '?': /* upside-down question mark */ #ifndef NO_LATIN1_CHARSET - s = (char)0xbf; /* ? */ + s = (char)0xbf; #endif - break; - case 'a': /* ae ligature */ + break; + case 'a': /* ae ligature */ #ifndef NO_LATIN1_CHARSET - s = (char)0xe6; ++*i; /* ? */ + s = (char)0xe6; ++*i; #else - s = 'e'; ++*i; + s = 'e'; ++*i; #endif - break; - case 'A': /* AE ligature */ + break; + case 'A': /* AE ligature */ #ifndef NO_LATIN1_CHARSET - s = (char)0xc6; ++*i; /* ? */ + s = (char)0xc6; ++*i; #else - s = 'E'; ++*i; + s = 'E'; ++*i; #endif - break; - case 'c': /* cents symbol */ + break; + case 'c': /* cents symbol */ #ifndef NO_LATIN1_CHARSET - s = (char)0xa2; /* ? */ + s = (char)0xa2; #endif - break; - case 'L': /* British pound */ + break; + case 'L': /* British pound */ #ifndef NO_LATIN1_CHARSET - s = (char)0xa3; /* ? */ + s = (char)0xa3; #endif - break; - case 'Y': /* Japanese Yen */ + break; + case 'Y': /* Japanese Yen */ #ifndef NO_LATIN1_CHARSET - s = (char)0xa5; /* ? */ + s = (char)0xa5; #endif - break; - case '-': /* em dash */ + break; + case '-': /* em dash */ #ifndef NO_LATIN1_CHARSET - /* s = (char)0x97; */ /* ? */ + /* s = (char)0x97; */ #endif - break; - case '#': /* 3-digit decimal code */ - { - s = (char)((a[++*i] - '0') * 100); - s += (a[++*i] - '0') * 10; - s += (a[++*i] - '0'); + break; + case '#': /* 3-digit decimal code */ + { + s = (char)((a[++*i]-'0')*100); + s += (a[++*i]-'0')*10; + s += (a[++*i]-'0'); #ifdef NO_LATIN1_CHARSET - if ((unsigned)s>127) s = '?'; + if ((unsigned)s>127) s = '?'; #endif - } + } } if (skipbracket) { ++*i; - if (a[*i + 1] == ')')++*i; - if (s == ')') s = r; + if (a[*i+1]==')') ++*i; + if (s==')') s = r; } return s; } +#if !defined (GLK) /* not used for Glk */ + +HUGO_FILE TrytoOpen(char *f, char *p, char *d) +{ + char drive[MAXDRIVE], dir[MAXDIR], fname[MAXFILENAME], ext[MAXEXT]; + char envvar[32]; + HUGO_FILE tempfile; char temppath[MAXPATH]; + + /* Try to open the given, vanilla filename */ + if ((strcmp(f, "")) && (tempfile = HUGO_FOPEN(f, p))) + { + return tempfile; + } + + hugo_splitpath(f, drive, dir, fname, ext); /* file to open */ + + /* If the given filename doesn't already specify where to find it */ + if (!strcmp(drive, "") && !strcmp(dir, "")) + { + /* Check gamefile directory */ + hugo_makepath(temppath, "", gamepath, fname, ext); + + if ((tempfile = HUGO_FOPEN(temppath, p))) + { + strcpy(f, temppath); /* the new pathname */ + return tempfile; + } + + /* Check environment variables */ + strcpy(envvar, "hugo_"); /* the actual var. name */ + strcat(envvar, d); + + if (getenv(strupr(envvar))) + { + hugo_makepath(temppath, "", getenv(strupr(envvar)), fname, ext); + + if ((tempfile = HUGO_FOPEN(temppath, p))) + { + strcpy(f, temppath); /* the new pathname */ + return tempfile; + } + } + } + + return NULL; /* return NULL if not openable */ +} + +#endif /* GLK */ + int Hugo::Undo() { int count = 0, n; int turns, turncount, tempptr; int obj, prop, attr, v; unsigned int addr; - if (--undoptr < 0) undoptr = MAXUNDO - 1; + if (--undoptr < 0) undoptr = MAXUNDO-1; - if (undostack[undoptr][1] != 0) + if (undostack[undoptr][1]!=0) { /* Get the number of operations to be undone for - the last turn. + the last turn. */ if ((turns = undostack[undoptr][1]) >= MAXUNDO) goto CheckUndoFailed; @@ -1763,121 +2200,122 @@ int Hugo::Undo() { tempptr = undoptr; /* Count the number of operations available to see if there - are enough to undo the last turn (as per the number - required in <turns>. + are enough to undo the last turn (as per the number + required in <turns>. */ do { - if (--undoptr < 0) undoptr = MAXUNDO - 1; + if (--undoptr < 0) undoptr = MAXUNDO-1; turncount++; /* if end of turn */ - if (undostack[undoptr][0] == 0) + if (undostack[undoptr][0]==0) break; - } while (true); + } + while (true); if (turncount<turns) goto CheckUndoFailed; undoptr = tempptr; - if (--undoptr < 0) undoptr = MAXUNDO - 1; + if (--undoptr < 0) undoptr = MAXUNDO-1; while (undostack[undoptr][0] != 0) { switch (undostack[undoptr][0]) { - case MOVE_T: - { - MoveObj(undostack[undoptr][1], undostack[undoptr][2]); - count++; - break; - } - - case PROP_T: - { - obj = undostack[undoptr][1]; - prop = undostack[undoptr][2]; - n = undostack[undoptr][3]; - v = undostack[undoptr][4]; + case MOVE_T: + { + MoveObj(undostack[undoptr][1], undostack[undoptr][2]); + count++; + break; + } - if ((addr = PropAddr(obj, prop, 0)) != 0) + case PROP_T: { - defseg = proptable; + obj = undostack[undoptr][1]; + prop = undostack[undoptr][2]; + n = undostack[undoptr][3]; + v = undostack[undoptr][4]; - if (n == PROP_ROUTINE) + if ((addr = PropAddr(obj, prop, 0))!=0) { - Poke(addr + 1, PROP_ROUTINE); - n = 1; - } + defseg = proptable; - /* Use this new prop count number if the - existing one is too low or a prop routine - */ - else if (Peek(addr + 1) == PROP_ROUTINE || Peek(addr + 1)<(unsigned char)n) - Poke(addr + 1, (unsigned char)n); + if (n==PROP_ROUTINE) + { + Poke(addr+1, PROP_ROUTINE); + n = 1; + } - /* property length */ - if (n <= (int)Peek(addr + 1)) - PokeWord(addr + 2 + (n - 1) * 2, v); + /* Use this new prop count number if the + existing one is too low or a prop routine + */ + else if (Peek(addr+1)==PROP_ROUTINE || Peek(addr+1)<(unsigned char)n) + Poke(addr+1, (unsigned char)n); + + /* property length */ + if (n<=(int)Peek(addr+1)) + PokeWord(addr+2+(n-1)*2, v); + } + count++; + break; } - count++; - break; - } - case ATTR_T: - { - obj = undostack[undoptr][1]; - attr = undostack[undoptr][2]; - n = undostack[undoptr][3]; - SetAttribute(obj, attr, n); - count++; - break; - } + case ATTR_T: + { + obj = undostack[undoptr][1]; + attr = undostack[undoptr][2]; + n = undostack[undoptr][3]; + SetAttribute(obj, attr, n); + count++; + break; + } - case VAR_T: - { - n = undostack[undoptr][1]; - v = undostack[undoptr][2]; - var[n] = v; - count++; - break; - } + case VAR_T: + { + n = undostack[undoptr][1]; + v = undostack[undoptr][2]; + var[n] = v; + count++; + break; + } - case ARRAYDATA_T: - { - defseg = arraytable; - addr = undostack[undoptr][1]; - n = undostack[undoptr][2]; - v = undostack[undoptr][3]; + case ARRAYDATA_T: + { + defseg = arraytable; + addr = undostack[undoptr][1]; + n = undostack[undoptr][2]; + v = undostack[undoptr][3]; /* The array length was already accounted for before calling - SaveUndo(), so there is no adjustment of - +2 here. + SaveUndo(), so there is no adjustment of + +2 here. */ - PokeWord(addr + n * 2, v); - count++; - break; - } + PokeWord(addr+n*2, v); + count++; + break; + } - case DICT_T: - { - defseg = dicttable; - PokeWord(0, --dictcount); - count++; - break; - } - case WORD_T: - { - n = undostack[undoptr][1]; - v = undostack[undoptr][2]; - wd[n] = v; - word[n] = GetWord(wd[n]); - count++; - } + case DICT_T: + { + defseg = dicttable; + PokeWord(0, --dictcount); + count++; + break; + } + case WORD_T: + { + n = undostack[undoptr][1]; + v = undostack[undoptr][2]; + wd[n] = v; + word[n] = GetWord(wd[n]); + count++; + } } defseg = gameseg; - if (--undoptr < 0) undoptr = MAXUNDO - 1; + if (--undoptr < 0) undoptr = MAXUNDO-1; } } @@ -1895,5 +2333,50 @@ CheckUndoFailed: return 1; } +/* + * Random-number generator replacement by Andrew Plotkin: + * + */ + +#if defined (BUILD_RANDOM) + +static unsigned int rand_table[55]; /* state for the RNG */ +static int rand_index1, rand_index2; + +int random() +{ + rand_index1 = (rand_index1 + 1) % 55; + rand_index2 = (rand_index2 + 1) % 55; + rand_table[rand_index1] = rand_table[rand_index1] - rand_table[rand_index2]; + return rand_table[rand_index1]; +} + +void srandom(int seed) +{ + int k = 1; + int i, loop; + + rand_table[54] = seed; + rand_index1 = 0; + rand_index2 = 31; + + for (i = 0; i < 55; i++) + { + int ii = (21 * i) % 55; + + rand_table[ii] = k; + k = seed - k; + seed = rand_table[ii]; + } + + for (loop = 0; loop < 4; loop++) + { + for (i = 0; i < 55; i++) + rand_table[i] = rand_table[i] - rand_table[ (1 + i + 30) % 55]; + } +} + +#endif /* BUILD_RANDOM */ + } // End of namespace Hugo } // End of namespace Glk diff --git a/engines/glk/hugo/hugo.cpp b/engines/glk/hugo/hugo.cpp index a5fbdb935f..0fca43222a 100644 --- a/engines/glk/hugo/hugo.cpp +++ b/engines/glk/hugo/hugo.cpp @@ -65,9 +65,10 @@ Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam arrexpr(0), multiprop(0), set_value(0) #if defined (DEBUGGER) , debug_eval(false), debug_eval_error(false), debugger_step_over(false), - debugger_finish(false), debugger_run(false), currentroutine(false), - complex_prop_breakpoint(false), trace_complex_prop_routine(false), properties(0), - current_locals(0) + debugger_finish(false), debugger_run(false), debugger_interrupt(false), + debugger_skip(false), runtime_error(false), currentroutine(false), + complex_prop_breakpoint(false), trace_complex_prop_routine(false), routines(0), + properties(0), current_locals(0), this_codeptr(0) #endif { // heexpr diff --git a/engines/glk/hugo/hugo.h b/engines/glk/hugo/hugo.h index de64744df6..1f5aaffa3e 100644 --- a/engines/glk/hugo/hugo.h +++ b/engines/glk/hugo/hugo.h @@ -220,6 +220,9 @@ private: bool debugger_step_over; bool debugger_finish; bool debugger_run; + bool debugger_interrupt; + bool debugger_skip; + bool runtime_error; int currentroutine; bool complex_prop_breakpoint; bool trace_complex_prop_routine; @@ -227,11 +230,13 @@ private: char *propertyname[MAX_PROPERTY]; // CODE code[999]; CALL call[999]; + int routines; int properties; WINDOW window[99]; int codeline[9][100]; char localname[9][100]; int current_locals; + long this_codeptr; #endif private: /** @@ -469,7 +474,9 @@ private: * Print to client display taking into account cursor relocation, * font changes, color setting, and window scrolling. */ - void Printout(char *a); + void Printout(char *a, int no_scrollback_linebreak); + + void PromptMore(); int RecordCommands(); @@ -558,6 +565,12 @@ private: const char *RoutineName(long loc) { return "Routine"; } void AddStringtoCodeWindow(const char *str) {} + + void SwitchtoDebugger() {} + + void DebuggerFatal(DEBUGGER_ERROR err) { error("Debugger error"); } + + void RecoverLastGood() {} #endif int Child(int obj); @@ -612,6 +625,42 @@ private: int Youngest(int obj); /**@}*/ + + /** + * \defgroup Miscellaneous + * @{ + */ + + int hugo_fseek(Common::SeekableReadStream *s, long int offset, int whence) { + return s->seek(offset, whence); + } + + int hugo_fgetc(Common::SeekableReadStream *s) { + return s->readByte(); + } + + bool hugo_ferror(Common::SeekableReadStream *s) const { + return s->err(); + } + + long hugo_ftell(Common::SeekableReadStream *s) { + return s->pos(); + } + + int hugo_fclose(strid_t f) { + delete f; + return 0; + } + + void hugo_exit(const char *msg) { + error("%s", line); + } + + size_t hugo_fread(void *ptr, size_t size, size_t count, Common::SeekableReadStream *s) { + return s->read(ptr, size * count); + } + + /**@}*/ private: /** * Allocate memory block @@ -651,10 +700,10 @@ public: void hugo_closefiles() {} void RunRoutine(long v) {} unsigned int FindWord(const char *a) { return 0; } - void PromptMore() {} void hugo_stopsample() {} void hugo_stopmusic() {} int hugo_hasgraphics() { return 0; } + int hugo_writetoscript(const char *s) { return 0; } }; } // End of namespace Hugo diff --git a/engines/glk/hugo/hugo_defines.h b/engines/glk/hugo/hugo_defines.h index ce2d0061fd..7809ea19b8 100644 --- a/engines/glk/hugo/hugo_defines.h +++ b/engines/glk/hugo/hugo_defines.h @@ -153,6 +153,8 @@ browsing. #define CODE_WINDOW 2 #endif +#define PRINTFATALERROR(a) error(a) + } // End of namespace Hugo } // End of namespace Glk diff --git a/engines/glk/hugo/hugo_types.h b/engines/glk/hugo/hugo_types.h index 3d7af86894..dacde03d54 100644 --- a/engines/glk/hugo/hugo_types.h +++ b/engines/glk/hugo/hugo_types.h @@ -120,6 +120,10 @@ struct CODE_BLOCK { }; #if defined (DEBUGGER) +enum DEBUGGER_ERROR { + D_MEMORY_ERROR +}; + struct CALL { long addr; bool param; |