mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-03 23:31:57 +00:00
1553 lines
38 KiB
C++
1553 lines
38 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "glk/jacl/jacl.h"
|
|
#include "glk/jacl/csv.h"
|
|
#include "glk/jacl/types.h"
|
|
#include "glk/jacl/language.h"
|
|
#include "glk/jacl/prototypes.h"
|
|
#include "glk/jacl/version.h"
|
|
|
|
namespace Glk {
|
|
namespace JACL {
|
|
|
|
int convert_to_utf32(unsigned char *text);
|
|
|
|
uint status_width, status_height;
|
|
|
|
schanid_t sound_channel[8] = { NULL, NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL
|
|
};
|
|
|
|
event_t *cancelled_event;
|
|
|
|
extern struct csv_parser parser_csv;
|
|
|
|
extern char text_buffer[];
|
|
extern const char *word[];
|
|
extern short int quoted[];
|
|
extern short int punctuated[];
|
|
extern int wp;
|
|
|
|
extern int custom_error;
|
|
extern int interrupted;
|
|
|
|
extern int jpp_error;
|
|
|
|
extern int it;
|
|
extern int them[];
|
|
extern int her;
|
|
extern int him;
|
|
|
|
extern int oops_word;
|
|
|
|
#ifdef WINGLK
|
|
struct string_type *resolved_string;
|
|
#endif
|
|
|
|
char include_directory[81] = "\0";
|
|
char temp_directory[81] = "\0";
|
|
char data_directory[81] = "\0";
|
|
char special_prompt[81] = "\n: \0";
|
|
char file_prompt[5] = ": \0";
|
|
char bookmark[81] = "\0";
|
|
char walkthru[81] = "\0";
|
|
|
|
char function_name[81];
|
|
|
|
extern char default_function[84];
|
|
char override_[81];
|
|
|
|
char temp_buffer[1024];
|
|
char error_buffer[1024];
|
|
unsigned char chunk_buffer[4096];
|
|
#ifndef NOUNICODE
|
|
glui32 chunk_buffer_uni[4096];
|
|
#endif
|
|
char proxy_buffer[1024];
|
|
|
|
char oops_buffer[1024];
|
|
char oopsed_current[1024];
|
|
char last_command[1024];
|
|
const char *blank_command = "blankjacl\0";
|
|
const char *current_command = (const char *)NULL;
|
|
char command_buffer[1024];
|
|
#ifndef NOUNICODE
|
|
glui32 command_buffer_uni[1024];
|
|
#endif
|
|
char players_command[1024];
|
|
|
|
int walkthru_running = FALSE;
|
|
|
|
int start_of_last_command;
|
|
int start_of_this_command;
|
|
|
|
int objects, integers, functions, strings;
|
|
int jpp_error = FALSE;
|
|
|
|
/* A STREAM FOR THE GAME FILE, WHEN IT'S OPEN. */
|
|
strid_t game_stream = NULL;
|
|
|
|
/* THE STREAM FOR OPENING UP THE ARCHIVE CONTAINING GRAPHICS AND SOUND */
|
|
strid_t blorb_stream;
|
|
|
|
/* A FILE REFERENCE FOR THE TRANSCRIPT FILE. */
|
|
static frefid_t script_fref = NULL;
|
|
/* A STREAM FOR THE TRANSCRIPT FILE, WHEN IT'S OPEN. */
|
|
static strid_t script_stream = NULL;
|
|
|
|
int noun[4];
|
|
int player = 0;
|
|
|
|
int noun3_backup;
|
|
int player_backup = 0;
|
|
|
|
int variable_contents;
|
|
int oec;
|
|
int *object_element_address,
|
|
*object_backup_address;
|
|
|
|
short int spaced = TRUE;
|
|
|
|
int delay = 0;
|
|
|
|
/* START OF GLK STUFF */
|
|
|
|
/* POINTERS TO THE GLK WINDOWS */
|
|
winid_t mainwin = NULL;
|
|
winid_t statuswin = NULL;
|
|
winid_t promptwin = NULL;
|
|
winid_t inputwin = NULL;
|
|
winid_t current_window = NULL;
|
|
|
|
/* POINTERS TO THE WINDOWS STREAMS */
|
|
strid_t mainstr = NULL;
|
|
strid_t statusstr = NULL;
|
|
strid_t promptstr = NULL;
|
|
strid_t inputstr = NULL;
|
|
|
|
/* END OF GLK STUFF */
|
|
|
|
char user_id[] = "local";
|
|
char prefix[81] = "\0";
|
|
char blorb[81] = "\0";
|
|
char game_path[256] = "\0";
|
|
char game_file[256] = "\0";
|
|
char processed_file[256] = "\0";
|
|
|
|
struct object_type *object[MAX_OBJECTS];
|
|
struct integer_type *integer_table = NULL;
|
|
struct cinteger_type *cinteger_table = NULL;
|
|
struct window_type *window_table = NULL;
|
|
struct attribute_type *attribute_table = NULL;
|
|
struct string_type *string_table = NULL;
|
|
struct string_type *cstring_table = NULL;
|
|
struct function_type *function_table = NULL;
|
|
struct function_type *executing_function = NULL;
|
|
struct command_type *completion_list = NULL;
|
|
struct word_type *grammar_table = NULL;
|
|
struct synonym_type *synonym_table = NULL;
|
|
struct filter_type *filter_table = NULL;
|
|
|
|
// Forward declarations
|
|
static void word_check();
|
|
static void version_info();
|
|
|
|
|
|
void glk_main() {
|
|
int index;
|
|
|
|
override_[0] = 0;
|
|
|
|
/* ALLOC AN EVENT TO STORE A CANCELLED EVENT IN */
|
|
if ((cancelled_event = (event_t *) malloc(sizeof(event_t))) == NULL)
|
|
outofmem();
|
|
|
|
/* CREATE style_User1 FOR USE IN THE STATUS LINE */
|
|
g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
|
|
g_vm->glk_stylehint_set(wintype_TextBuffer, style_User2, stylehint_ReverseColor, 1);
|
|
|
|
/* OPEN THE MAIN WINDOW THE GLK WINDOWS */
|
|
mainwin = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
|
|
|
|
if (!mainwin) {
|
|
/* IT'S POSSIBLE THAT THE MAIN WINDOW FAILED TO OPEN. THERE's
|
|
* NOTHING WE CAN DO WITHOUT IT, SO EXIT. */
|
|
return;
|
|
} else {
|
|
/* GET A REFERENCE TO mainwin's STREAM */
|
|
mainstr = g_vm->glk_window_get_stream(mainwin);
|
|
}
|
|
|
|
/* SET THE CURRENT OUTPUT STREAM TO PRINT TO IT. */
|
|
jacl_set_window(mainwin);
|
|
|
|
/* OPEN A THIRD WINDOW: A TEXT GRID, BELOW THE MAIN WINDOW, ONE LINE
|
|
* HIGH. THIS IS THE WINDOW TO DISPLAY THE COMMAND PROMPT IN */
|
|
//promptwin = g_vm->glk_window_open(mainwin, winmethod_Below | winmethod_Fixed,
|
|
// 3, wintype_TextBuffer, 0);
|
|
|
|
/* SET THIS TO DETERMINE THE SYTEM OF INPUT TO USE */
|
|
//inputwin = promptwin;
|
|
inputwin = mainwin;
|
|
|
|
if (jpp_error) {
|
|
/* THERE WAS AN ERROR DURING PREPROCESSING. NOW THAT THERE IS AN
|
|
* OPEN GLK WINDOW, OUTPUT THE ERROR MESSAGE AND EXIT */
|
|
log_error(error_buffer, FALSE);
|
|
terminate(200);
|
|
return;
|
|
}
|
|
|
|
// INTIALISE THE CSV PARSER
|
|
csv_init(&parser_csv, CSV_APPEND_NULL);
|
|
|
|
/* NO PREPROCESSOR ERRORS, LOAD THE GAME FILE */
|
|
read_gamefile();
|
|
|
|
execute("+bootstrap");
|
|
|
|
// OPEN A SECOND WINDOW: A TEXT GRID, ABOVE THE MAIN WINDOW, ONE LINE
|
|
// HIGH. IT IS POSSIBLE THAT THIS WILL FAIL ALSO, BUT WE ACCEPT THAT.
|
|
statuswin = g_vm->glk_window_open(mainwin, winmethod_Above | winmethod_Fixed,
|
|
0, wintype_TextGrid, 0);
|
|
|
|
// GET A REFERENCE TO statuswin's STREAM
|
|
if (statuswin != NULL) {
|
|
statusstr = g_vm->glk_window_get_stream(statuswin);
|
|
}
|
|
|
|
#ifdef WINGLK
|
|
if ((resolved_string = cstring_resolve("game_title")) != NULL) {
|
|
wing_vm->glk_window_set_title(resolved_string->value);
|
|
} else {
|
|
sprintf(temp_buffer, "JACL v%d.%d.%d ", J_VERSION, J_RELEASE, J_BUILD);
|
|
wing_vm->glk_window_set_title(temp_buffer);
|
|
}
|
|
#endif
|
|
|
|
if (SOUND_SUPPORTED->value) {
|
|
/* CREATE THE EIGHT SOUND CHANNELS */
|
|
for (index = 0; index < 8; index++) {
|
|
sound_channel[index] = g_vm->glk_schannel_create(0);
|
|
}
|
|
}
|
|
|
|
jacl_set_window(mainwin);
|
|
|
|
execute("+intro");
|
|
|
|
if (object[2] == NULL) {
|
|
log_error(CANT_RUN, PLUS_STDERR);
|
|
terminate(43);
|
|
return;
|
|
}
|
|
|
|
|
|
/* DUMMY RETRIEVE OF 'HERE' FOR TESTING OF GAME STATE */
|
|
get_here();
|
|
|
|
eachturn();
|
|
|
|
/* TOP OF COMMAND LOOP */
|
|
while (!g_vm->shouldQuit()) {
|
|
int gotline;
|
|
event_t ev;
|
|
|
|
custom_error = FALSE;
|
|
|
|
jacl_set_window(mainwin);
|
|
|
|
execute("+bottom");
|
|
|
|
status_line();
|
|
|
|
if (current_command != NULL) {
|
|
strcpy(last_command, current_command);
|
|
}
|
|
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
jacl_set_window(inputwin);
|
|
}
|
|
|
|
// If loading a savegame from the launcher, do it now
|
|
if (g_vm->loadingSavegame()) {
|
|
// Load the game
|
|
if (g_vm->loadLauncherSavegame()) {
|
|
// Do a look action
|
|
const uint32 LOOK[5] = { 'l', 'o', 'o', 'k', 0 };
|
|
Common::copy(LOOK, LOOK + 5, command_buffer_uni);
|
|
ev.val1 = 4;
|
|
} else {
|
|
continue;
|
|
}
|
|
} else {
|
|
/* OUTPUT THE CUSTOM COMMAND PROMPT */
|
|
write_text(string_resolve("command_prompt")->value);
|
|
|
|
#ifdef NOUNICODE
|
|
g_vm->glk_request_line_event(inputwin, command_buffer, 255, 0);
|
|
#else
|
|
g_vm->glk_request_line_event_uni(inputwin, command_buffer_uni, 255, 0);
|
|
#endif
|
|
|
|
jacl_set_window(inputwin);
|
|
|
|
gotline = FALSE;
|
|
|
|
while (!gotline) {
|
|
/* GRAB AN EVENT. */
|
|
g_vm->glk_select(&ev);
|
|
if (g_vm->shouldQuit())
|
|
return;
|
|
|
|
switch (ev.type) {
|
|
|
|
case evtype_LineInput:
|
|
if (ev.window == inputwin) {
|
|
gotline = TRUE;
|
|
jacl_set_window(mainwin);
|
|
/* REALLY THE EVENT CAN *ONLY* BE FROM MAINWIN,
|
|
* BECAUSE WE NEVER REQUEST LINE INPUT FROM THE
|
|
* STATUS WINDOW. BUT WE DO A PARANOIA TEST,
|
|
* BECAUSE COMMANDBUF IS ONLY FILLED IF THE LINE
|
|
* EVENT COMES FROM THE MAINWIN REQUEST. IF THE
|
|
* LINE EVENT COMES FROM ANYWHERE ELSE, WE IGNORE
|
|
* IT. */
|
|
}
|
|
break;
|
|
|
|
case evtype_SoundNotify:
|
|
/* A SOUND HAS FINISHED PLAYING CALL +sound_finished
|
|
* WITH THE RESOUCE NUMBER AS THE FIRST ARGUMENT
|
|
* AND THE CHANNEL NUMBER AS THE SECOND ARGUMENT */
|
|
sprintf(temp_buffer, "+sound_finished<%d<%d", (int) ev.val1, (int) ev.val2 - 1);
|
|
execute(temp_buffer);
|
|
break;
|
|
|
|
case evtype_Timer:
|
|
/* A TIMER EVENT IS TRIGGERED PERIODICALLY IF THE GAME
|
|
* REQUESTS THEM. THIS SIMPLY EXECUTES THE FUNCTION
|
|
* +timer WHICH IS LIKE +eachturn EXCEPT IT DOESN'T
|
|
* WAIT FOR THE PLAYER TO TYPE A COMMAND */
|
|
|
|
jacl_set_window(mainwin);
|
|
execute("+timer");
|
|
break;
|
|
|
|
case evtype_Arrange:
|
|
/* WINDOWS HAVE CHANGED SIZE, SO WE HAVE TO REDRAW THE
|
|
* STATUS WINDOW. */
|
|
status_line();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// THE PLAYER'S INPUT WILL BE UTF-32. CONVERT IT TO UTF-8 AND NULL TERMINATE IT
|
|
#ifndef NOUNICODE
|
|
convert_to_utf8(command_buffer_uni, ev.val1);
|
|
#endif
|
|
|
|
current_command = command_buffer;
|
|
|
|
/* SET ALL THE OUTPUT TO GO TO mainwin NOW THE COMMAND HAS BEEN READ */
|
|
if (inputwin == promptwin) {
|
|
jacl_set_window(mainwin);
|
|
write_text(string_resolve("command_prompt")->value);
|
|
g_vm->glk_set_style(style_Input);
|
|
write_text(current_command);
|
|
g_vm->glk_set_style(style_Normal);
|
|
write_text("^");
|
|
}
|
|
|
|
execute("+top");
|
|
|
|
index = 0;
|
|
|
|
if (*current_command) {
|
|
while (*(current_command + index) && index < 1024) {
|
|
if (*(current_command + index) == '\r' || *(current_command + index) == '\n') {
|
|
break;
|
|
} else {
|
|
text_buffer[index] = *(current_command + index);
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
text_buffer[index] = 0;
|
|
|
|
if (text_buffer[0] == 0) {
|
|
/* NO COMMAND WAS SPECIFIED, FILL THE COMMAND IN AS 'blankjacl'
|
|
* FOR THE GAME TO PROCESS AS DESIRED */
|
|
strcpy(text_buffer, "blankjacl");
|
|
current_command = blank_command;
|
|
}
|
|
|
|
command_encapsulate();
|
|
jacl_truncate();
|
|
|
|
index = 0;
|
|
|
|
/* SET THE INTEGER INTERRUPTED TO FALSE. IF THIS IS SET TO
|
|
* TRUE BY ANY COMMAND, FURTHER PROCESSING WILL STOP */
|
|
INTERRUPTED->value = FALSE;
|
|
|
|
interrupted = FALSE;
|
|
|
|
if (word[0] != NULL) {
|
|
if (strcmp(word[0], "undo")) {
|
|
/* COMMAND DOES NOT EQUAL undo */
|
|
save_game_state();
|
|
}
|
|
|
|
if (word[0][0] == '*') {
|
|
if (script_stream) {
|
|
write_text(cstring_resolve("COMMENT_RECORDED")->value);
|
|
} else {
|
|
write_text(cstring_resolve("COMMENT_IGNORED")->value);
|
|
}
|
|
} else {
|
|
/* COMMAND IS NOT NULL, START PROCESSING IT */
|
|
preparse();
|
|
}
|
|
} else {
|
|
/* NO COMMAND WAS SPECIFIED, FILL THE COMMAND IN AS 'blankjacl'
|
|
* FOR THE GAME TO PROCESS AS DESIRED */
|
|
strcpy(text_buffer, "blankjacl");
|
|
command_encapsulate();
|
|
preparse();
|
|
}
|
|
}
|
|
}
|
|
|
|
void preparse() {
|
|
int position;
|
|
|
|
// THE INTERRUPTED VARIABLE IS USED TO STOP LATER ACTIONS IN A COMMAND
|
|
// IF ANY ONE
|
|
while (word[wp] != NULL && INTERRUPTED->value == FALSE) {
|
|
//printf("--- preparse %s\n", word[wp]);
|
|
// PROCESS THE CURRENT COMMAND
|
|
// CREATE THE command STRINGS FROM THIS POINT ONWARDS SO THE VERB OF
|
|
// THE CURRENT COMMAND IS ALWAYS command[0].
|
|
|
|
clear_cstring("command");
|
|
|
|
position = wp;
|
|
|
|
while (word[position] != NULL && strcmp(word[position], cstring_resolve("THEN_WORD")->value)) {
|
|
add_cstring("command", word[position]);
|
|
position++;
|
|
};
|
|
|
|
// PROCESS THE COMMAND
|
|
word_check();
|
|
|
|
/* THE PREVIOUS COMMAND HAS FINISHED, LOOK FOR ANOTHER COMMAND */
|
|
while (word[wp] != NULL) {
|
|
if (word[wp] != NULL && !strcmp(word[wp], cstring_resolve("THEN_WORD")->value)) {
|
|
wp++;
|
|
break;
|
|
}
|
|
wp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void word_check() {
|
|
int index;
|
|
|
|
/* REMEMBER THE START OF THIS COMMAND TO SUPPORT 'oops' AND 'again' */
|
|
start_of_this_command = wp;
|
|
//printf("--- command starts at %d\n", start_of_this_command);
|
|
|
|
/* START CHECKING THE PLAYER'S COMMAND FOR SYSTEM COMMANDS */
|
|
if (!strcmp(word[wp], cstring_resolve("QUIT_WORD")->value) || !strcmp(word[wp], "q")) {
|
|
if (execute("+quit_game") == FALSE) {
|
|
TIME->value = FALSE;
|
|
write_text(cstring_resolve("SURE_QUIT")->value);
|
|
if (get_yes_or_no()) {
|
|
newline();
|
|
execute("+score");
|
|
terminate(0);
|
|
return;
|
|
} else {
|
|
write_text(cstring_resolve("RETURN_GAME")->value);
|
|
}
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("RESTART_WORD")->value)) {
|
|
if (execute("+restart_game") == FALSE) {
|
|
TIME->value = FALSE;
|
|
write_text(cstring_resolve("SURE_RESTART")->value);
|
|
if (get_yes_or_no()) {
|
|
write_text(cstring_resolve("RESTARTING")->value);
|
|
restart_game();
|
|
g_vm->glk_window_clear(current_window);
|
|
execute("+intro");
|
|
eachturn();
|
|
} else {
|
|
write_text(cstring_resolve("RETURN_GAME")->value);
|
|
}
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("UNDO_WORD")->value)) {
|
|
if (execute("+undo_move") == FALSE) {
|
|
undoing();
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("OOPS_WORD")->value) || !strcmp(word[wp], "o")) {
|
|
//printf("--- oops word is %d\n", oops_word);
|
|
if (word[++wp] != NULL) {
|
|
if (oops_word == -1) {
|
|
if (TOTAL_MOVES->value == 0) {
|
|
write_text(cstring_resolve("NO_MOVES")->value);
|
|
TIME->value = FALSE;
|
|
} else {
|
|
write_text(cstring_resolve("CANT_CORRECT")->value);
|
|
TIME->value = FALSE;
|
|
}
|
|
} else {
|
|
strcpy(oops_buffer, word[wp]);
|
|
strcpy(text_buffer, last_command);
|
|
command_encapsulate();
|
|
//printf("--- trying to replace %s with %s\n", word[oops_word], oops_buffer);
|
|
jacl_truncate();
|
|
word[oops_word] = (char *)&oops_buffer;
|
|
|
|
/* BUILD A PLAIN STRING REPRESENTING THE NEW COMMAND */
|
|
oopsed_current[0] = 0;
|
|
index = 0;
|
|
|
|
while (word[index] != NULL) {
|
|
if (oopsed_current[0] != 0) {
|
|
strcat(oopsed_current, " ");
|
|
}
|
|
|
|
strcat(oopsed_current, word[index]);
|
|
|
|
index++;
|
|
}
|
|
|
|
current_command = oopsed_current;
|
|
//printf("--- current command is: %s\n", current_command);
|
|
|
|
/* PROCESS THE FIXED COMMAND ONLY */
|
|
wp = start_of_last_command;
|
|
word_check();
|
|
}
|
|
} else {
|
|
write_text(cstring_resolve("BAD_OOPS")->value);
|
|
TIME->value = FALSE;
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("AGAIN_WORD")->value) || !strcmp(word[wp], "g")) {
|
|
if (TOTAL_MOVES->value == 0) {
|
|
write_text(cstring_resolve("NO_MOVES")->value);
|
|
TIME->value = FALSE;
|
|
} else if (last_command[0] == 0) {
|
|
write_text(cstring_resolve("NOT_CLEVER")->value);
|
|
TIME->value = FALSE;
|
|
} else {
|
|
strcpy(text_buffer, last_command);
|
|
current_command = last_command;
|
|
command_encapsulate();
|
|
jacl_truncate();
|
|
//printf("--- command started at %d\n", start_of_last_command);
|
|
wp = start_of_last_command;
|
|
word_check();
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("SCRIPT_WORD")->value) || !strcmp(word[wp], "transcript")) {
|
|
scripting();
|
|
} else if (!strcmp(word[wp], cstring_resolve("UNSCRIPT_WORD")->value)) {
|
|
if (!script_stream) {
|
|
write_text(cstring_resolve("SCRIPTING_ALREADY_OFF")->value);
|
|
} else {
|
|
/* Close the file. */
|
|
g_vm->glk_put_string_stream(script_stream, "\nEND OF A TRANSCRIPT\n");
|
|
g_vm->glk_stream_close(script_stream, NULL);
|
|
write_text(cstring_resolve("SCRIPTING_OFF")->value);
|
|
script_stream = NULL;
|
|
}
|
|
} else if (!strcmp(word[wp], cstring_resolve("WALKTHRU_WORD")->value)) {
|
|
walking_thru();
|
|
} else if (!strcmp(word[wp], cstring_resolve("INFO_WORD")->value) || !strcmp(word[wp], "version")) {
|
|
version_info();
|
|
write_text("you can redistribute it and/or modify it under the ");
|
|
write_text("terms of the GNU General Public License as published by ");
|
|
write_text("the Free Software Foundation; either version 2 of the ");
|
|
write_text("License, or any later version.^^");
|
|
write_text("This program is distributed in the hope that it will be ");
|
|
write_text("useful, but WITHOUT ANY WARRANTY; without even the ");
|
|
write_text("implied warranty of MERCHANTABILITY or FITNESS FOR A ");
|
|
write_text("PARTICULAR PURPOSE. See the GNU General Public License ");
|
|
write_text("for more details.^^");
|
|
write_text("You should have received a copy of the GNU General ");
|
|
write_text("Public License along with this program; if not, write ");
|
|
write_text("to the Free Software Foundation, Inc., 675 Mass Ave, ");
|
|
write_text("Cambridge, MA 02139, USA.^^");
|
|
sprintf(temp_buffer, "OBJECTS DEFINED: %d^", objects);
|
|
write_text(temp_buffer);
|
|
TIME->value = FALSE;
|
|
} else {
|
|
/* NO WORD HAS BEEN MARKED AS AN ERROR YET*/
|
|
oops_word = -1;
|
|
|
|
/* THIS IS NOT A SYSTEM COMMAND, CALL parser TO PROCESS THE COMMAND */
|
|
parser();
|
|
}
|
|
|
|
start_of_last_command = start_of_this_command;
|
|
}
|
|
|
|
void version_info() {
|
|
char buffer[80];
|
|
|
|
sprintf(buffer, "JACL Interpreter v%d.%d.%d ", J_VERSION, J_RELEASE,
|
|
J_BUILD);
|
|
write_text(buffer);
|
|
sprintf(buffer, "/ %d object.^", MAX_OBJECTS);
|
|
write_text(buffer);
|
|
write_text("Copyright (c) 1992-2010 Stuart Allen.^^");
|
|
}
|
|
|
|
void save_game_state() {
|
|
/* THIS FUNCTION MAKES AN IN-MEMORY COPY OF THE GAME STATE AFTER EACH
|
|
* OF THE PLAYER'S COMMANDS SO THE 'undo' COMMAND CAN BE USED */
|
|
int index,
|
|
counter;
|
|
|
|
struct integer_type *current_integer = integer_table;
|
|
struct function_type *current_function = function_table;
|
|
|
|
do {
|
|
current_function->call_count_backup = current_function->call_count;
|
|
current_function = current_function->next_function;
|
|
} while (current_function != NULL);
|
|
|
|
do {
|
|
current_integer->value_backup = current_integer->value;
|
|
current_integer = current_integer->next_integer;
|
|
} while (current_integer != NULL);
|
|
|
|
for (index = 1; index <= objects; index++) {
|
|
if (object[index]->nosave)
|
|
continue;
|
|
|
|
for (counter = 0; counter < 16; counter++) {
|
|
object[index]->integer_backup[counter] =
|
|
object[index]->integer[counter];
|
|
}
|
|
|
|
object[index]->attributes_backup = object[index]->attributes;
|
|
object[index]->user_attributes_backup = object[index]->user_attributes;
|
|
}
|
|
|
|
player_backup = player;
|
|
noun3_backup = noun[3];
|
|
}
|
|
|
|
int save_interaction() {
|
|
if (g_vm->saveGame().getCode() == Common::kNoError) {
|
|
return (TRUE);
|
|
} else {
|
|
write_text(cstring_resolve("CANT_SAVE")->value);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
void restore_game_state() {
|
|
/* THIS FUNCTION IS CALLED AS A RESULT OF THE PLAYER USING THE 'undo'
|
|
* COMMAND */
|
|
int index,
|
|
counter;
|
|
|
|
struct integer_type *current_integer = integer_table;
|
|
struct function_type *current_function = function_table;
|
|
|
|
do {
|
|
current_function->call_count = current_function->call_count_backup;
|
|
current_function = current_function->next_function;
|
|
} while (current_function != NULL);
|
|
|
|
|
|
do {
|
|
current_integer->value = current_integer->value_backup;
|
|
current_integer = current_integer->next_integer;
|
|
} while (current_integer != NULL);
|
|
|
|
for (index = 1; index <= objects; index++) {
|
|
if (object[index]->nosave)
|
|
continue;
|
|
|
|
for (counter = 0; counter < 16; counter++)
|
|
object[index]->integer[counter] =
|
|
object[index]->integer_backup[counter];
|
|
|
|
object[index]->attributes = object[index]->attributes_backup;
|
|
object[index]->user_attributes = object[index]->user_attributes_backup;
|
|
}
|
|
|
|
player = player_backup;
|
|
noun[3] = noun3_backup;
|
|
|
|
write_text(cstring_resolve("MOVE_UNDONE")->value);
|
|
object[HERE]->attributes &= ~1;
|
|
execute("+top");
|
|
execute("+look_around");
|
|
execute("+bottom");
|
|
TIME->value = FALSE;
|
|
}
|
|
|
|
void write_text(const char *string_buffer) {
|
|
int index, length;
|
|
if (g_vm->loadingSavegame())
|
|
return;
|
|
|
|
if (!strcmp(string_buffer, "tilde")) {
|
|
g_vm->glk_put_string("~");
|
|
return;
|
|
} else if (!strcmp(string_buffer, "caret")) {
|
|
g_vm->glk_put_string("^");
|
|
return;
|
|
}
|
|
|
|
length = strlen(string_buffer);
|
|
|
|
for (index = 0; index < length; index++) {
|
|
if (*(string_buffer + index) == '^') {
|
|
chunk_buffer[index] = '\n';
|
|
} else if (*(string_buffer + index) == '~') {
|
|
chunk_buffer[index] = '\"';
|
|
} else {
|
|
chunk_buffer[index] = *(string_buffer + index);
|
|
}
|
|
}
|
|
|
|
chunk_buffer[index] = 0;
|
|
|
|
/* PRINT THE CONTENTS OF string_buffer */
|
|
#ifdef NOUNICODE
|
|
g_vm->glk_put_string(chunk_buffer);
|
|
#else
|
|
chunk_buffer_uni[(glui32) convert_to_utf32(chunk_buffer)] = 0;
|
|
g_vm->glk_put_string_uni(chunk_buffer_uni);
|
|
#endif
|
|
}
|
|
|
|
void jacl_sleep(unsigned int mseconds) {
|
|
g_system->delayMillis(mseconds);
|
|
}
|
|
|
|
void status_line() {
|
|
int cursor, index;
|
|
winid_t pair_window;
|
|
|
|
if (!statuswin) {
|
|
return;
|
|
} else {
|
|
// THERE IS AN EXISTING STATUS WINDOW, MAKE SURE A NEW SIZE HASN'T BEEN
|
|
// REQUESTED
|
|
g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
|
|
if (status_height != (uint)integer_resolve("status_window")->value) {
|
|
// HEIGHT HAS CHANGED, UPDATE THE WINDOW
|
|
pair_window = g_vm->glk_window_get_parent(statuswin);
|
|
g_vm->glk_window_set_arrangement(pair_window, winmethod_Above | winmethod_Fixed, integer_resolve("status_window")->value, statuswin);
|
|
g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
|
|
}
|
|
}
|
|
|
|
if (status_height == 0) {
|
|
// THE STATUS WINDOW CAN'T BE CLOSED, ONLY SET TO HAVE A HEIGHT OF ZERO
|
|
return;
|
|
}
|
|
|
|
jacl_set_window(statuswin);
|
|
g_vm->glk_window_clear(statuswin);
|
|
|
|
if (execute("+update_status_window") == FALSE) {
|
|
g_vm->glk_set_style(style_User1);
|
|
|
|
/* DISPLAY THE INVERSE STATUS LINE AT THE TOP OF THE SCREEN */
|
|
for (index = 0; index < (int)status_width; index++) {
|
|
temp_buffer[index] = ' ';
|
|
}
|
|
temp_buffer[index] = 0;
|
|
write_text(temp_buffer);
|
|
|
|
/* PRINT THE LOCATION'S TITLE ON THE LEFT. */
|
|
g_vm->glk_window_move_cursor(statuswin, 1, 0);
|
|
write_text(sentence_output(HERE, TRUE));
|
|
|
|
/* BUILD THE SCORE/ MOVES STRING */
|
|
temp_buffer[0] = 0;
|
|
sprintf(temp_buffer, "Score: %d Moves: %d", SCORE->value, TOTAL_MOVES->value);
|
|
|
|
cursor = status_width - strlen(temp_buffer);
|
|
cursor--;
|
|
g_vm->glk_window_move_cursor(statuswin, cursor, 0);
|
|
write_text(temp_buffer);
|
|
}
|
|
|
|
jacl_set_window(mainwin);
|
|
|
|
}
|
|
|
|
void newline() {
|
|
/* START A NEW LINE ON THE SCREEN */
|
|
write_text("\n");
|
|
}
|
|
|
|
void more(const char *message) {
|
|
jacl_set_window(inputwin);
|
|
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
newline();
|
|
}
|
|
|
|
g_vm->glk_set_style(style_Emphasized);
|
|
write_text(message);
|
|
g_vm->glk_set_style(style_Normal);
|
|
|
|
(void)get_key();
|
|
|
|
if (inputwin == mainwin) newline();
|
|
}
|
|
|
|
int get_key() {
|
|
event_t ev;
|
|
|
|
g_vm->glk_request_char_event(inputwin);
|
|
|
|
while (!g_vm->shouldQuit()) {
|
|
g_vm->glk_select(&ev);
|
|
|
|
switch (ev.type) {
|
|
case evtype_CharInput:
|
|
if (ev.window == inputwin) {
|
|
return (ev.val1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_number(int insist, int low, int high) {
|
|
char *cx;
|
|
char commandbuf[256];
|
|
int response;
|
|
int gotline;
|
|
event_t ev;
|
|
|
|
status_line();
|
|
|
|
sprintf(temp_buffer, cstring_resolve("TYPE_NUMBER")->value, low, high);
|
|
|
|
/* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
|
|
|
|
while (1) {
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
jacl_set_window(inputwin);
|
|
}
|
|
|
|
write_text(temp_buffer);
|
|
jacl_set_window(mainwin);
|
|
|
|
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
|
|
|
|
gotline = FALSE;
|
|
while (!gotline && g_vm->shouldQuit()) {
|
|
g_vm->glk_select(&ev);
|
|
|
|
switch (ev.type) {
|
|
case evtype_LineInput:
|
|
if (ev.window == inputwin) {
|
|
gotline = TRUE;
|
|
}
|
|
break;
|
|
|
|
case evtype_Arrange:
|
|
status_line();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
commandbuf[ev.val1] = '\0';
|
|
for (cx = commandbuf; *cx == ' '; cx++) { };
|
|
|
|
if (validate(cx)) {
|
|
response = atoi(cx);
|
|
if (response >= low && response <= high) {
|
|
return (response);
|
|
}
|
|
}
|
|
|
|
if (!insist) {
|
|
return (-1);
|
|
} else {
|
|
write_text(cstring_resolve("INVALID_SELECTION")->value);
|
|
}
|
|
}
|
|
}
|
|
|
|
void get_string(char *string_buffer) {
|
|
char *cx;
|
|
char commandbuf[256];
|
|
int gotline;
|
|
event_t ev;
|
|
|
|
status_line();
|
|
|
|
/* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
|
|
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
jacl_set_window(inputwin);
|
|
}
|
|
|
|
jacl_set_window(mainwin);
|
|
|
|
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
|
|
|
|
gotline = FALSE;
|
|
while (!gotline && !g_vm->shouldQuit()) {
|
|
g_vm->glk_select(&ev);
|
|
|
|
switch (ev.type) {
|
|
case evtype_LineInput:
|
|
if (ev.window == inputwin) {
|
|
gotline = TRUE;
|
|
}
|
|
break;
|
|
|
|
case evtype_Arrange:
|
|
status_line();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
commandbuf[ev.val1] = '\0';
|
|
for (cx = commandbuf; *cx == ' '; cx++) { };
|
|
|
|
// COPY UP TO 255 BYTES OF THE ENTERED TEXT INTO THE SUPPLIED STRING
|
|
strncpy(string_buffer, cx, 255);
|
|
}
|
|
|
|
int get_yes_or_no() {
|
|
char *cx;
|
|
char commandbuf[256];
|
|
int gotline;
|
|
event_t ev;
|
|
|
|
status_line();
|
|
|
|
/* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
|
|
|
|
while (1) {
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
jacl_set_window(inputwin);
|
|
}
|
|
|
|
write_text(cstring_resolve("YES_OR_NO")->value);
|
|
jacl_set_window(mainwin);
|
|
|
|
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
|
|
|
|
gotline = FALSE;
|
|
while (!gotline && !g_vm->shouldQuit()) {
|
|
|
|
g_vm->glk_select(&ev);
|
|
|
|
switch (ev.type) {
|
|
case evtype_LineInput:
|
|
if (ev.window == inputwin) {
|
|
gotline = TRUE;
|
|
}
|
|
break;
|
|
|
|
case evtype_Arrange:
|
|
status_line();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
commandbuf[ev.val1] = '\0';
|
|
for (cx = commandbuf; *cx == ' '; cx++) { };
|
|
|
|
// PUSH THE FIRST NON-SPACE CHARACTER TO LOWER FOR COMPARISON
|
|
// WITH CONSTANT
|
|
*cx = tolower(*cx);
|
|
|
|
if (*cx == cstring_resolve("YES_WORD")->value[0]) {
|
|
return TRUE;
|
|
} else if (*cx == cstring_resolve("NO_WORD")->value[0]) {
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
char get_character(const char *message) {
|
|
char *cx;
|
|
char commandbuf[256];
|
|
int gotline;
|
|
event_t ev;
|
|
|
|
status_line();
|
|
|
|
/* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
|
|
|
|
while (!g_vm->shouldQuit()) {
|
|
if (inputwin == promptwin) {
|
|
g_vm->glk_window_clear(promptwin);
|
|
jacl_set_window(inputwin);
|
|
}
|
|
|
|
write_text(message);
|
|
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
|
|
jacl_set_window(mainwin);
|
|
|
|
gotline = FALSE;
|
|
while (!gotline && !g_vm->shouldQuit()) {
|
|
|
|
g_vm->glk_select(&ev);
|
|
|
|
switch (ev.type) {
|
|
case evtype_LineInput:
|
|
if (ev.window == inputwin) {
|
|
gotline = TRUE;
|
|
}
|
|
break;
|
|
|
|
case evtype_Arrange:
|
|
status_line();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
commandbuf[ev.val1] = '\0';
|
|
for (cx = commandbuf; *cx == ' '; cx++) { };
|
|
|
|
return (*cx);
|
|
}
|
|
|
|
|
|
return '\0';
|
|
}
|
|
|
|
strid_t open_glk_file(uint usage, uint mode, char *filename) {
|
|
|
|
frefid_t file_reference;
|
|
strid_t stream_reference;
|
|
|
|
file_reference = g_vm->glk_fileref_create_by_name(usage, filename, 0);
|
|
|
|
if (file_reference) {
|
|
stream_reference = g_vm->glk_stream_open_file(file_reference, (FileMode)mode, 0);
|
|
|
|
if (stream_reference) {
|
|
/* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
|
|
* HAS BEEN SUCCESSFULLY OPENED */
|
|
g_vm->glk_fileref_destroy(file_reference);
|
|
|
|
return (stream_reference);
|
|
}
|
|
}
|
|
|
|
return (strid_t) NULL;
|
|
}
|
|
|
|
void scripting() {
|
|
if (script_stream) {
|
|
write_text(cstring_resolve("SCRIPTING_ALREADY_ON")->value);
|
|
return;
|
|
}
|
|
|
|
/* IF WE'VE TURNED ON SCRIPTING BEFORE, USE THE SAME FILE REFERENCE;
|
|
* OTHERWISE, PROMPT THE PLAYER FOR A FILE. */
|
|
if (!script_fref) {
|
|
script_fref = g_vm->glk_fileref_create_by_prompt(
|
|
fileusage_Transcript | fileusage_TextMode,
|
|
filemode_WriteAppend, 0);
|
|
if (!script_fref) {
|
|
write_text(cstring_resolve("CANT_WRITE_SCRIPT")->value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* OPEN THE TRANSCRIPT FILE */
|
|
script_stream = g_vm->glk_stream_open_file(script_fref, filemode_WriteAppend, 0);
|
|
|
|
if (!script_stream) {
|
|
write_text(cstring_resolve("CANT_WRITE_SCRIPT")->value);
|
|
return;
|
|
}
|
|
write_text(cstring_resolve("SCRIPTING_ON")->value);
|
|
g_vm->glk_window_set_echo_stream(mainwin, script_stream);
|
|
g_vm->glk_put_string_stream(script_stream, "TRANSCRIPT OF: ");
|
|
g_vm->glk_put_string_stream(script_stream, cstring_resolve("game_title")->value);
|
|
g_vm->glk_put_string_stream(script_stream, "\n");
|
|
}
|
|
|
|
void undoing() {
|
|
if (TOTAL_MOVES->value && strcmp(last_command, cstring_resolve("UNDO_WORD")->value)) {
|
|
restore_game_state();
|
|
} else {
|
|
write_text(cstring_resolve("NO_UNDO")->value);
|
|
TIME->value = FALSE;
|
|
}
|
|
}
|
|
|
|
void walking_thru() {
|
|
int result, index;
|
|
|
|
int length;
|
|
char script_line[81];
|
|
|
|
/* A FILE REFERENCE FOR THE WALKTHRU FILE. */
|
|
frefid_t walkthru_fref = NULL;
|
|
|
|
/* A STREAM FOR THE WALKTHRU FILE, WHEN IT'S OPEN. */
|
|
strid_t walkthru_stream = NULL;
|
|
|
|
walkthru_fref = g_vm->glk_fileref_create_by_prompt(fileusage_Data | fileusage_TextMode, filemode_Read, 0);
|
|
|
|
if (!walkthru_fref) {
|
|
write_text(cstring_resolve("ERROR_READING_WALKTHRU")->value);
|
|
return;
|
|
}
|
|
|
|
/* OPEN THE WALKTHRU FILE */
|
|
walkthru_stream = g_vm->glk_stream_open_file(walkthru_fref, filemode_Read, 0);
|
|
|
|
if (!walkthru_stream) {
|
|
write_text(cstring_resolve("ERROR_READING_WALKTHRU")->value);
|
|
return;
|
|
}
|
|
|
|
walkthru_running = TRUE;
|
|
|
|
/* ISSUE ALL THE COMMANDS STORE IN THE WALKTHRU FILE */
|
|
|
|
/* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
|
|
* HAS BEEN SUCCESSFULLY OPENED */
|
|
g_vm->glk_fileref_destroy(walkthru_fref);
|
|
|
|
result = g_vm->glk_get_line_stream(walkthru_stream, text_buffer, (glui32) 80);
|
|
|
|
/* SET TO LOWER CASE AND STRIP NEWLINES */
|
|
length = strlen(text_buffer);
|
|
for (index = 0; index < length; index++) {
|
|
if (text_buffer[index] == '\r' ||
|
|
text_buffer[index] == '\n') {
|
|
text_buffer[index] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcpy(script_line, text_buffer);
|
|
|
|
while (result && INTERRUPTED->value == FALSE) {
|
|
/* THERE COULD BE A LOT OF PROCESSING GOING ON HERE BEFORE GETTING
|
|
* TO THE NEXT EVENT LOOP SO CALL g_vm->glk_tick AFTER EACH LINE READ */
|
|
g_vm->glk_tick();
|
|
command_encapsulate();
|
|
jacl_truncate();
|
|
if (word[0] != NULL) {
|
|
custom_error = FALSE;
|
|
|
|
execute("+bottom");
|
|
|
|
write_text(string_resolve("command_prompt")->value);
|
|
g_vm->glk_set_style(style_Input);
|
|
write_text(script_line);
|
|
newline();
|
|
g_vm->glk_set_style(style_Normal);
|
|
|
|
execute("+top");
|
|
|
|
preparse();
|
|
}
|
|
|
|
result = g_vm->glk_get_line_stream(walkthru_stream, text_buffer, (glui32) 80);
|
|
|
|
/* SET TO LOWER CASE AND STRIP NEWLINES */
|
|
length = strlen(text_buffer);
|
|
for (index = 0; index < length; index++) {
|
|
if (text_buffer[index] == '\r' ||
|
|
text_buffer[index] == '\n') {
|
|
text_buffer[index] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcpy(script_line, text_buffer);
|
|
}
|
|
|
|
/* CLOSE THE STREAM */
|
|
g_vm->glk_stream_close(walkthru_stream, NULL);
|
|
|
|
/* FINISH UP */
|
|
walkthru_running = FALSE;
|
|
}
|
|
|
|
int restore_interaction() {
|
|
if (g_vm->loadGame().getCode() != Common::kNoError) {
|
|
write_text(cstring_resolve("CANT_RESTORE")->value);
|
|
return (FALSE);
|
|
} else {
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
glui32 glk_get_bin_line_stream(strid_t file_stream, char *buffer, glui32 max_length) {
|
|
int character = 0;
|
|
|
|
register int index = 0;
|
|
|
|
character = g_vm->glk_get_char_stream(file_stream);
|
|
while (character != -1 && index < (int) max_length) {
|
|
*(buffer + index) = (char) character;
|
|
index++;
|
|
if (character == (int) '\n' ||
|
|
character == (int) '\r') {
|
|
break;
|
|
}
|
|
character = g_vm->glk_get_char_stream(file_stream);
|
|
};
|
|
|
|
*(buffer + index) = 0;
|
|
|
|
return ((glui32) index);
|
|
}
|
|
|
|
void jacl_set_window(winid_t new_window) {
|
|
current_window = new_window;
|
|
g_vm->glk_set_window(new_window);
|
|
}
|
|
|
|
#ifdef READLINE
|
|
char **command_completion(const char *text, int start, int end) {
|
|
/* READLINE TAB COMPLETION CODE */
|
|
char **options;
|
|
|
|
options = (const char **) NULL;
|
|
|
|
if (start == 0)
|
|
options = completion_matches(text, verb_generator);
|
|
else
|
|
options = completion_matches(text, object_generator);
|
|
|
|
return (options);
|
|
}
|
|
#endif
|
|
|
|
const char *object_generator(const char *text, int state) {
|
|
static int len;
|
|
static struct command_type *now;
|
|
struct command_type *to_send;
|
|
struct name_type *current_name = (struct name_type *) NULL;
|
|
|
|
/* IF THIS IS A NEW WORD TO COMPLETE, INITIALIZE NOW. THIS INCLUDES
|
|
SAVING THE LENGTH OF TEXT FOR EFFICIENCY, AND INITIALIZING THE INDEX
|
|
VARIABLE TO 0. */
|
|
|
|
if (!state) {
|
|
/* BUILD THE LIST */
|
|
int index;
|
|
completion_list = NULL;
|
|
|
|
/* LOOP THROUGH ALL THE OBJECTS AND SEE IF THEY ARE IN
|
|
THE CURRENT LOCATION */
|
|
for (index = 1; index <= objects; index++) {
|
|
if (parent_of(HERE, index, UNRESTRICT) && !(object[index]->attributes & NO_TAB)) {
|
|
/* LOOP THROUGH ALL THE OBJECTS NAMES AND
|
|
THEM TO THE COMPLETION LIST */
|
|
current_name = object[index]->first_name;
|
|
while (current_name) {
|
|
add_word(current_name->name);
|
|
current_name = current_name->next_name;
|
|
}
|
|
}
|
|
}
|
|
now = completion_list;
|
|
len = strlen(text);
|
|
}
|
|
|
|
while (now != NULL) {
|
|
if (!strncmp(text, now->word, len)) {
|
|
to_send = now;
|
|
now = now->next;
|
|
return ((const char *)to_send->word);
|
|
}
|
|
now = now->next;
|
|
}
|
|
|
|
return (const char *)NULL;
|
|
}
|
|
|
|
const char *verb_generator(const char *text, int state) {
|
|
static int len;
|
|
static struct command_type *now;
|
|
struct command_type *to_send;
|
|
struct word_type *pointer;
|
|
|
|
/* IF THIS IS A NEW WORD TO COMPLETE, INITIALIZE NOW. THIS INCLUDES
|
|
SAVING THE LENGTH OF TEXT FOR EFFICIENCY, AND INITIALIZING THE INDEX
|
|
VARIABLE TO 0. */
|
|
|
|
if (!state) {
|
|
/* BUILD THE LIST */
|
|
completion_list = NULL;
|
|
|
|
pointer = grammar_table;
|
|
while (pointer != NULL) {
|
|
add_word(pointer->word);
|
|
pointer = pointer->next_sibling;
|
|
}
|
|
|
|
add_word("walkthru");
|
|
|
|
now = completion_list;
|
|
len = strlen(text);
|
|
}
|
|
|
|
while (now != NULL) {
|
|
if (!strncmp(text, now->word, len)) {
|
|
to_send = now;
|
|
now = now->next;
|
|
|
|
/* MALLOC A COPY AND RETURN A POINTER TO THE COPY */
|
|
return ((const char *)to_send->word);
|
|
}
|
|
now = now->next;
|
|
}
|
|
|
|
return (const char *)NULL;
|
|
}
|
|
|
|
/* ADD A COPY OF STRING TO A LIST OF STRINGS IF IT IS NOT
|
|
ALREADY IN THE LIST. THIS IS FOR THE USE OF READLINE */
|
|
void add_word(const char *newWord) {
|
|
static struct command_type *current_word = NULL;
|
|
struct command_type *previous_word = NULL;
|
|
|
|
/* DON'T ADD WORDS SUCH AS *present TO THE LIST*/
|
|
if (*newWord == '*')
|
|
return;
|
|
|
|
if (current_word != NULL)
|
|
previous_word = current_word;
|
|
|
|
current_word = (struct command_type *) malloc(sizeof(struct command_type));
|
|
|
|
if (current_word != NULL) {
|
|
if (completion_list == NULL) {
|
|
completion_list = current_word;
|
|
}
|
|
|
|
strncpy(current_word->word, newWord, 40);
|
|
current_word->word[40] = 0;
|
|
current_word->next = NULL;
|
|
|
|
if (previous_word != NULL) {
|
|
previous_word->next = current_word;
|
|
}
|
|
}
|
|
}
|
|
|
|
void convert_to_utf8(glui32 *text, int len) {
|
|
int i, k;
|
|
|
|
i = 0;
|
|
k = 0;
|
|
|
|
/*convert UTF-32 to UTF-8 */
|
|
while (i < len) {
|
|
if (text[i] < 0x80) {
|
|
command_buffer[k] = text[i];
|
|
k++;
|
|
} else if (text[i] < 0x800) {
|
|
command_buffer[k ] = (0xC0 | ((text[i] & 0x7C0) >> 6));
|
|
command_buffer[k + 1] = (0x80 | (text[i] & 0x03F));
|
|
k = k + 2;
|
|
} else if (text[i] < 0x10000) {
|
|
command_buffer[k ] = (0xE0 | ((text[i] & 0xF000) >> 12));
|
|
command_buffer[k + 1] = (0x80 | ((text[i] & 0x0FC0) >> 6));
|
|
command_buffer[k + 2] = (0x80 | (text[i] & 0x003F));
|
|
k = k + 3;
|
|
} else if (text[i] < 0x200000) {
|
|
command_buffer[k ] = (0xF0 | ((text[i] & 0x1C0000) >> 18));
|
|
command_buffer[k + 1] = (0x80 | ((text[i] & 0x03F000) >> 12));
|
|
command_buffer[k + 2] = (0x80 | ((text[i] & 0x000FC0) >> 6));
|
|
command_buffer[k + 3] = (0x80 | (text[i] & 0x00003F));
|
|
k = k + 4;
|
|
} else {
|
|
command_buffer[k] = '?';
|
|
k++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
/* null-terminated string */
|
|
command_buffer[k] = '\0';
|
|
}
|
|
|
|
#ifndef NOUNICODE
|
|
int convert_to_utf32(unsigned char *text) {
|
|
int text_len;
|
|
int rlen;
|
|
|
|
if (!text) {
|
|
return 0;
|
|
}
|
|
|
|
text_len = strlen((const char *)text);
|
|
|
|
if (!text_len) {
|
|
return 0;
|
|
}
|
|
|
|
rlen = (int) parse_utf8(text, text_len, chunk_buffer_uni, text_len);
|
|
|
|
return (rlen);
|
|
}
|
|
|
|
glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen) {
|
|
glui32 pos = 0;
|
|
glui32 outpos = 0;
|
|
glui32 res;
|
|
glui32 val0, val1, val2, val3;
|
|
|
|
while (outpos < outlen) {
|
|
if (pos >= buflen)
|
|
break;
|
|
|
|
val0 = buf[pos++];
|
|
|
|
if (val0 < 0x80) {
|
|
res = val0;
|
|
out[outpos++] = res;
|
|
continue;
|
|
}
|
|
|
|
if ((val0 & 0xe0) == 0xc0) {
|
|
if (pos + 1 > buflen) {
|
|
warning("incomplete two-byte character");
|
|
break;
|
|
}
|
|
val1 = buf[pos++];
|
|
if ((val1 & 0xc0) != 0x80) {
|
|
warning("malformed two-byte character");
|
|
break;
|
|
}
|
|
res = (val0 & 0x1f) << 6;
|
|
res |= (val1 & 0x3f);
|
|
out[outpos++] = res;
|
|
continue;
|
|
}
|
|
|
|
if ((val0 & 0xf0) == 0xe0) {
|
|
if (pos + 2 > buflen) {
|
|
warning("incomplete three-byte character");
|
|
break;
|
|
}
|
|
val1 = buf[pos++];
|
|
val2 = buf[pos++];
|
|
if ((val1 & 0xc0) != 0x80) {
|
|
warning("malformed three-byte character");
|
|
break;
|
|
}
|
|
if ((val2 & 0xc0) != 0x80) {
|
|
warning("malformed three-byte character");
|
|
break;
|
|
}
|
|
res = (((val0 & 0xf) << 12) & 0x0000f000);
|
|
res |= (((val1 & 0x3f) << 6) & 0x00000fc0);
|
|
res |= (((val2 & 0x3f)) & 0x0000003f);
|
|
out[outpos++] = res;
|
|
continue;
|
|
}
|
|
|
|
if ((val0 & 0xf0) == 0xf0) {
|
|
if ((val0 & 0xf8) != 0xf0) {
|
|
warning("malformed four-byte character");
|
|
break;
|
|
}
|
|
if (pos + 3 > buflen) {
|
|
warning("incomplete four-byte character");
|
|
break;
|
|
}
|
|
val1 = buf[pos++];
|
|
val2 = buf[pos++];
|
|
val3 = buf[pos++];
|
|
if ((val1 & 0xc0) != 0x80) {
|
|
warning("malformed four-byte character");
|
|
break;
|
|
}
|
|
if ((val2 & 0xc0) != 0x80) {
|
|
warning("malformed four-byte character");
|
|
break;
|
|
}
|
|
if ((val3 & 0xc0) != 0x80) {
|
|
warning("malformed four-byte character");
|
|
break;
|
|
}
|
|
res = (((val0 & 0x7) << 18) & 0x1c0000);
|
|
res |= (((val1 & 0x3f) << 12) & 0x03f000);
|
|
res |= (((val2 & 0x3f) << 6) & 0x000fc0);
|
|
res |= (((val3 & 0x3f)) & 0x00003f);
|
|
out[outpos++] = res;
|
|
continue;
|
|
}
|
|
|
|
warning("malformed character");
|
|
}
|
|
|
|
return outpos;
|
|
}
|
|
#endif
|
|
|
|
} // End of namespace JACL
|
|
} // End of namespace Glk
|