Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <sfx_iterator_internal.h>
#include <sfx_engine.h>
#include <sfx_core.h>
#include <resource.h>
#define DUMMY_SOUND_HANDLE 0xdeadbeef
static song_iterator_t *
build_iterator(resource_mgr_t *resmgr, int song_nr, int type, songit_id_t id) {
resource_t *song = scir_find_resource(resmgr, sci_sound, song_nr, 0);
if (!song)
return NULL;
return songit_new(song->data, song->size, type, id);
}
int main(int argc, char** argv) {
resource_mgr_t *resmgr;
sfx_state_t sound;
int res_version = SCI_VERSION_AUTODETECT;
int sound_nr;
song_handle_t dummy1;
int dummy2;
int arg;
int it_type = SCI_SONG_ITERATOR_TYPE_SCI0;
song_iterator_t *base, *ff;
printf("FreeSCI %s music player Copyright (C) 1999-2007\n", VERSION);
printf(" Dmitry Jemerov, Christopher T. Lansdown, Sergey Lapin, Rickard Lind,\n"
" Carl Muckenhoupt, Christoph Reichenbach, Magnus Reftel, Lars Skovlund,\n"
" Rink Springer, Petr Vyhnak, Solomon Peachy, Matt Hargett, Alex Angas\n"
" Walter van Niftrik, Rainer Canavan, Ruediger Hanke, Hugues Valois\n"
"This program is free software. You can copy and/or modify it freely\n"
"according to the terms of the GNU general public license, v2.0\n"
"or any later version, at your option.\n"
"It comes with ABSOLUTELY NO WARRANTY.\n");
if (argc < 3) {
fprintf(stderr, "Syntax: %s <resource dir> <sound number> [<sound number> ...]\n", argv[0]);
return 1;
}
if (!(resmgr = scir_new_resource_manager(argv[1], res_version,
0, 1024 * 128))) {
fprintf(stderr, "Could not find any resources; quitting.\n");
return 2;
}
if (resmgr->sci_version >= SCI_VERSION_01)
it_type = SCI_SONG_ITERATOR_TYPE_SCI1;
sfx_init(&sound, resmgr, 0);
sfx_set_volume(&sound, 127);
arg = 2 - 1;
while (++arg < argc) {
sound_nr = atoi(argv[arg]);
base = ff = build_iterator(resmgr, sound_nr, it_type,
DUMMY_SOUND_HANDLE);
printf("Playing resource %d...\n", sound_nr);
if (sfx_add_song(&sound, ff,
0, DUMMY_SOUND_HANDLE, sound_nr)) {
fprintf(stderr, "Could not start sound resource. Does it exist?\n");
return 2;
}
sfx_song_set_status(&sound, DUMMY_SOUND_HANDLE, SOUND_STATUS_PLAYING);
while (sfx_poll(&sound, &dummy1, &dummy2) != SI_FINISHED) {}
}
sfx_exit(&sound);
scir_free_resource_manager(resmgr);
return 0;
}

983
devtools/sci/scidisasm.cpp Normal file
View File

@@ -0,0 +1,983 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#define MALLOC_DEBUG
#include <sciresource.h>
#include <engine.h>
#include <console.h>
#include <versions.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif /* HAVE_GETOPT_H */
static int hexdump = 0;
static int opcode_size = 0;
static int verbose = 0;
static resource_mgr_t *resmgr;
#ifdef HAVE_GETOPT_LONG
static struct option options[] = {
{"version", no_argument, 0, 256},
{"help", no_argument, 0, 'h'},
{"hexdump", no_argument, &hexdump, 1},
{"opcode-size", no_argument, &opcode_size, 1},
{"verbose", no_argument, &verbose, 1},
{"gamedir", required_argument, 0, 'd'},
{0, 0, 0, 0}
};
#endif /* HAVE_GETOPT_LONG */
#define SCI_ASSUME_VERSION SCI_VERSION_FTU_NEW_SCRIPT_HEADER
typedef struct name_s {
int offset;
char *name;
int class_no;
struct name_s *next;
} name_t;
typedef struct area_s {
int start_offset;
int end_offset;
void *data;
struct area_s *next;
} area_t;
enum area_type { area_said, area_string, area_object, area_last };
typedef struct script_state_s {
int script_no;
name_t *names;
area_t *areas [area_last];
struct script_state_s *next;
} script_state_t;
typedef struct disasm_state_s {
char **snames;
int selector_count;
opcode *opcodes;
int kernel_names_nr;
char **kernel_names;
word_t **words;
int word_count;
char **class_names;
int *class_selector_count;
short **class_selectors;
int class_count;
int old_header;
script_state_t *scripts;
} disasm_state_t;
void
disassemble_script(disasm_state_t *d, int res_no, int pass_no);
script_state_t *
find_script_state(disasm_state_t *d, int script_no);
void
script_free_names(script_state_t *s);
void
script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no);
char *
script_find_name(script_state_t *s, int offset, int *class_no);
void
script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data);
void
script_free_areas(script_state_t *s);
int
script_get_area_type(script_state_t *s, int offset, void **pdata);
void
disasm_init(disasm_state_t *d);
void
disasm_free_state(disasm_state_t *d);
int main(int argc, char** argv) {
int i;
char outfilename [256];
int optindex = 0;
int c;
disasm_state_t disasm_state;
char *gamedir = NULL;
int res_version = SCI_VERSION_AUTODETECT;
#ifdef HAVE_GETOPT_LONG
while ((c = getopt_long(argc, argv, "vhxr:d:", options, &optindex)) > -1) {
#else /* !HAVE_GETOPT_H */
while ((c = getopt(argc, argv, "vhxr:d:")) > -1) {
#endif /* !HAVE_GETOPT_H */
switch (c) {
case 256:
printf("scidisasm ("PACKAGE") "VERSION"\n");
printf("This program is copyright (C) 1999 Christoph Reichenbach.\n"
"It comes WITHOUT WARRANTY of any kind.\n"
"This is free software, released under the GNU General Public License.\n");
exit(0);
case 'h':
printf("Usage: scidisasm\n"
"\nAvailable options:\n"
" --version Prints the version number\n"
" --help -h Displays this help message\n"
" --gamedir <dir> -d<dir> Read game resources from dir\n"
" --hexdump -x Hex dump all script resources\n"
" --verbose Print additional disassembly information\n"
" --opcode-size Print opcode size postfixes\n");
exit(0);
case 'd':
if (gamedir) sci_free(gamedir);
gamedir = sci_strdup(optarg);
break;
case 'r':
res_version = atoi(optarg);
break;
case 0: /* getopt_long already did this for us */
case '?':
/* getopt_long already printed an error message. */
break;
default:
return -1;
}
}
if (gamedir)
if (chdir(gamedir)) {
printf("Error changing to game directory '%s'\n", gamedir);
exit(1);
}
printf("Loading resources...\n");
if (!(resmgr = scir_new_resource_manager(sci_getcwd(), res_version,
1, 1024 * 128))) {
fprintf(stderr, "Could not find any resources; quitting.\n");
exit(1);
}
disasm_init(&disasm_state);
script_adjust_opcode_formats(resmgr->sci_version);
printf("Performing first pass...\n");
for (i = 0; i < resmgr->resources_nr; i++)
if (resmgr->resources[i].type == sci_script)
disassemble_script(&disasm_state,
resmgr->resources[i].number, 1);
printf("Performing second pass...\n");
for (i = 0; i < resmgr->resources_nr; i++)
if (resmgr->resources[i].type == sci_script) {
sprintf(outfilename, "%03d.script",
resmgr->resources[i].number);
open_console_file(outfilename);
disassemble_script(&disasm_state,
resmgr->resources[i].number, 2);
}
close_console_file();
disasm_free_state(&disasm_state);
free(resmgr->resource_path);
scir_free_resource_manager(resmgr);
return 0;
}
/* -- General operations on disasm_state_t ------------------------------- */
void
disasm_init(disasm_state_t *d) {
d->snames = vocabulary_get_snames(resmgr, &d->selector_count, SCI_ASSUME_VERSION);
d->opcodes = vocabulary_get_opcodes(resmgr);
d->kernel_names = vocabulary_get_knames(resmgr, &d->kernel_names_nr);
d->words = vocab_get_words(resmgr, &d->word_count);
d->scripts = NULL;
d->old_header = 0;
d->class_count = vocabulary_get_class_count(resmgr);
d->class_names = (char **) sci_malloc(d->class_count * sizeof(char *));
memset(d->class_names, 0, d->class_count * sizeof(char *));
d->class_selector_count = (int *) sci_malloc(d->class_count * sizeof(int));
memset(d->class_selector_count, 0, d->class_count * sizeof(int));
d->class_selectors = (short **) sci_malloc(d->class_count * sizeof(short *));
memset(d->class_selectors, 0, d->class_count * sizeof(short *));
}
void
disasm_free_state(disasm_state_t *d) {
script_state_t *s, *next_script;
int i;
s = d->scripts;
while (s) {
next_script = s->next;
script_free_names(s);
script_free_areas(s);
s = next_script;
}
for (i = 0; i < d->class_count; i++) {
if (d->class_names [i]) sci_free(d->class_names [i]);
if (d->class_selectors [i]) sci_free(d->class_selectors [i]);
}
free(d->class_names);
free(d->class_selectors);
free(d->class_selector_count);
vocabulary_free_snames(d->snames);
vocabulary_free_opcodes(d->opcodes);
vocabulary_free_knames(d->kernel_names);
vocab_free_words(d->words, d->word_count);
}
script_state_t *
find_script_state(disasm_state_t *d, int script_no) {
script_state_t *s;
for (s = d->scripts; s; s = s->next)
if (s->script_no == script_no) return s;
s = (script_state_t *) sci_malloc(sizeof(script_state_t));
memset(s, 0, sizeof(script_state_t));
s->script_no = script_no;
s->next = d->scripts;
d->scripts = s;
return s;
}
/* -- Name table operations ---------------------------------------------- */
void
script_free_names(script_state_t *s) {
name_t *p = s->names, *next_name;
while (p) {
next_name = p->next;
free(p->name);
free(p);
p = next_name;
}
s->names = NULL;
}
void
script_add_name(script_state_t *s, int aoffset, char *aname, int aclass_no) {
name_t *p;
char *name = script_find_name(s, aoffset, NULL);
if (name) return;
p = (name_t *) sci_malloc(sizeof(name_t));
p->offset = aoffset;
p->name = sci_strdup(aname);
p->class_no = aclass_no;
p->next = s->names;
s->names = p;
}
char *
script_find_name(script_state_t *s, int offset, int *aclass_no) {
name_t *p;
for (p = s->names; p; p = p->next)
if (p->offset == offset) {
if (aclass_no && p->class_no != -2) *aclass_no = p->class_no;
return p->name;
}
return NULL;
}
/* -- Area table operations ---------------------------------------------- */
void
script_add_area(script_state_t *s, int start_offset, int end_offset, int type, void *data) {
area_t *area;
area = (area_t *) sci_malloc(sizeof(area_t));
area->start_offset = start_offset;
area->end_offset = end_offset;
area->data = data;
area->next = s->areas [type];
s->areas [type] = area;
}
void
script_free_areas(script_state_t *s) {
int i;
for (i = 0; i < area_last; i++) {
area_t *area = s->areas [i], *next_area;
while (area) {
next_area = area->next;
free(area);
area = next_area;
}
}
}
int
script_get_area_type(script_state_t *s, int offset, void **pdata) {
int i;
for (i = 0; i < area_last; i++) {
area_t *area = s->areas [i];
while (area) {
if (area->start_offset <= offset && area->end_offset >= offset) {
if (pdata != NULL) *pdata = area->data;
return i;
}
area = area->next;
}
}
return -1;
}
char *
get_selector_name(disasm_state_t *d, int selector) {
static char selector_name [256];
if (d->snames && selector >= 0 && selector < d->selector_count)
return d->snames [selector];
else {
sprintf(selector_name, "unknown_sel_%X", selector);
return selector_name;
}
}
const char *
get_class_name(disasm_state_t *d, int class_no) {
static char class_name [256];
if (class_no == -1)
return "<none>";
else if (class_no >= 0 && class_no < d->class_count && d->class_names [class_no])
return d->class_names [class_no];
else {
sprintf(class_name, "class_%d", class_no);
return class_name;
}
}
/* -- Code to dump individual script block types ------------------------- */
static void
script_dump_object(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
int selectors, overloads, selectorsize;
int species = getInt16(data + 8 + seeker);
int superclass = getInt16(data + 10 + seeker);
int namepos = getInt16(data + 14 + seeker);
int i = 0;
short sel;
const char *name;
char buf [256];
short *sels;
selectors = (selectorsize = getInt16(data + seeker + 6));
name = namepos ? ((const char *)data + namepos) : "<unknown>";
if (pass_no == 1)
script_add_area(s, seeker, seeker + objsize - 1, area_object, strdup(name));
if (pass_no == 2) {
sciprintf(".object\n");
sciprintf("Name: %s\n", name);
sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass);
sciprintf("Species: %s [%x]\n", get_class_name(d, species), species);
sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff);
sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4));
sciprintf("Selectors [%x]:\n", selectors);
}
seeker += 8;
if (species < d->class_count)
sels = d->class_selectors [species];
else
sels = NULL;
while (selectors--) {
if (pass_no == 2) {
sel = getInt16(data + seeker) & 0xffff;
if (sels && (sels [i] >= 0) && (sels[i] < d->selector_count)) {
sciprintf(" [#%03x] %s = 0x%x\n", i, d->snames [sels [i]], sel);
i++;
} else
sciprintf(" [#%03x] <unknown> = 0x%x\n", i++, sel);
}
seeker += 2;
}
selectors = overloads = getInt16(data + seeker);
if (pass_no == 2)
sciprintf("Overloaded functions: %x\n", overloads);
seeker += 2;
while (overloads--) {
word selector = getInt16(data + (seeker)) & 0xffff;
if (d->old_header) selector >>= 1;
if (pass_no == 1) {
sprintf(buf, "%s::%s", name, get_selector_name(d, selector));
script_add_name(s, getInt16(data + seeker + selectors*2 + 2), buf, species);
} else {
sciprintf(" [%03x] %s: @", selector, get_selector_name(d, selector));
sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2));
}
seeker += 2;
}
}
static void
script_dump_class(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
word selectors, overloads, selectorsize;
int species = getInt16(data + 8 + seeker);
int superclass = getInt16(data + 10 + seeker);
int namepos = getInt16(data + 14 + seeker);
const char *name;
char buf [256];
int i;
name = namepos ? ((const char *)data + namepos) : "<unknown>";
selectors = (selectorsize = getInt16(data + seeker + 6));
if (pass_no == 1) {
if (species >= 0 && species < d->class_count) {
if (!namepos) {
sprintf(buf, "class_%d", species);
d->class_names [species] = sci_strdup(buf);
} else
d->class_names [species] = sci_strdup(name);
d->class_selector_count [species] = selectors;
d->class_selectors [species] = (short *) sci_malloc(sizeof(short) * selectors);
}
}
if (pass_no == 2) {
sciprintf(".class\n");
sciprintf("Name: %s\n", name);
sciprintf("Superclass: %s [%x]\n", get_class_name(d, superclass), superclass);
sciprintf("Species: %x\n", species);
sciprintf("-info-:%x\n", getInt16(data + 12 + seeker) & 0xffff);
sciprintf("Function area offset: %x\n", getInt16(data + seeker + 4));
sciprintf("Selectors [%x]:\n", selectors);
}
seeker += 8;
selectorsize <<= 1;
for (i = 0; i < selectors; i++) {
word selector = 0xffff & getInt16(data + (seeker) + selectorsize);
if (d->old_header) selector >>= 1;
if (pass_no == 1) {
if (species >= 0 && species < d->class_count)
d->class_selectors [species][i] = selector;
} else
sciprintf(" [%03x] %s = 0x%x\n", selector, get_selector_name(d, selector),
getInt16(data + seeker) & 0xffff);
seeker += 2;
}
seeker += selectorsize;
selectors = overloads = getInt16(data + seeker);
sciprintf("Overloaded functions: %x\n", overloads);
seeker += 2;
while (overloads--) {
word selector = getInt16(data + (seeker)) & 0xffff;
if (d->old_header) selector >>= 1;
if (pass_no == 1) {
sprintf(buf, "%s::%s", name, get_selector_name(d, selector));
script_add_name(s, getInt16(data + seeker + selectors*2 + 2) & 0xffff, buf, species);
} else {
sciprintf(" [%03x] %s: @", selector & 0xffff, get_selector_name(d, selector));
sciprintf("%04x\n", getInt16(data + seeker + selectors*2 + 2) & 0xffff);
}
seeker += 2;
}
}
static int
script_dump_said_string(disasm_state_t *d, unsigned char *data, int seeker) {
while (1) {
unsigned short nextitem = (unsigned char) data [seeker++];
if (nextitem == 0xFF) return seeker;
if (nextitem >= 0xF0) {
switch (nextitem) {
case 0xf0:
sciprintf(", ");
break;
case 0xf1:
sciprintf("& ");
break;
case 0xf2:
sciprintf("/ ");
break;
case 0xf3:
sciprintf("( ");
break;
case 0xf4:
sciprintf(") ");
break;
case 0xf5:
sciprintf("[ ");
break;
case 0xf6:
sciprintf("] ");
break;
case 0xf7:
sciprintf("# ");
break;
case 0xf8:
sciprintf("< ");
break;
case 0xf9:
sciprintf("> ");
break;
}
} else {
nextitem = nextitem << 8 | (unsigned char) data [seeker++];
sciprintf("%s ", vocab_get_any_group_word(nextitem, d->words, d->word_count));
if (verbose)
sciprintf("[%03x] ", nextitem);
}
}
}
static void
script_dump_said(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
int _seeker = seeker + objsize - 4;
if (pass_no == 1) {
script_add_area(s, seeker, seeker + objsize - 1, area_said, NULL);
return;
}
sciprintf(".said\n");
while (seeker < _seeker - 1) {
sciprintf("%04x: ", seeker);
seeker = script_dump_said_string(d, data, seeker);
sciprintf("\n");
}
}
static void
script_dump_synonyms(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
int _seeker = seeker + objsize - 4;
sciprintf("Synonyms:\n");
while (seeker < _seeker) {
int search = getInt16(data + seeker);
int replace = getInt16(data + seeker + 2);
seeker += 4;
if (search < 0) break;
sciprintf("%s[%03x] ==> %s[%03x]\n",
vocab_get_any_group_word(search, d->words, d->word_count), search,
vocab_get_any_group_word(replace, d->words, d->word_count), replace);
}
}
static void
script_dump_strings(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
int endptr = seeker + objsize - 4;
if (pass_no == 1) {
script_add_area(s, seeker, seeker + objsize - 1, area_string, NULL);
return;
}
sciprintf(".strings\n");
while (data [seeker] && seeker < endptr) {
sciprintf("%04x: %s\n", seeker, data + seeker);
seeker += strlen((char *) data + seeker) + 1;
}
}
static void
script_dump_exports(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
byte *pexport = (byte *)(data + seeker);
word export_count = getUInt16(pexport);
int i;
char buf [256];
pexport += 2;
if (pass_no == 2) sciprintf(".exports\n");
for (i = 0; i < export_count; i++) {
if (pass_no == 1) {
guint16 offset = getUInt16(pexport);
sprintf(buf, "exp_%02X", i);
script_add_name(s, offset, buf, -1);
} else
sciprintf("%02X: %04X\n", i, *pexport);
pexport += 2;
}
}
/* -- The disassembly code ----------------------------------------------- */
static void
script_disassemble_code(disasm_state_t *d, script_state_t *s,
unsigned char *data, int seeker, int objsize, int pass_no) {
int endptr = seeker + objsize - 4;
int i = 0;
int cur_class = -1;
word dest;
void *area_data;
char buf [256];
char *dest_name;
if (pass_no == 2) sciprintf(".code\n");
while (seeker < endptr - 1) {
unsigned char opsize = data [seeker];
unsigned char opcode = opsize >> 1;
word param_value;
char *name;
opsize &= 1; /* byte if true, word if false */
if (pass_no == 2) {
name = script_find_name(s, seeker, &cur_class);
if (name) sciprintf(" %s:\n", name);
sciprintf("%04X: ", seeker);
sciprintf("%s", d->opcodes[opcode].name);
if (opcode_size && formats[opcode][0])
sciprintf(".%c", opsize ? 'b' : 'w');
sciprintf("\t");
}
seeker++;
for (i = 0; formats[opcode][i]; i++)
switch (formats[opcode][i]) {
case Script_Invalid:
if (pass_no == 2) sciprintf("-Invalid operation-");
break;
case Script_SByte:
case Script_Byte:
if (pass_no == 2) sciprintf(" %02x", data[seeker]);
seeker++;
break;
case Script_Word:
case Script_SWord:
if (pass_no == 2)
sciprintf(" %04x", 0xffff & (data[seeker] | (data[seeker+1] << 8)));
seeker += 2;
break;
case Script_SVariable:
case Script_Variable:
case Script_Global:
case Script_Local:
case Script_Temp:
case Script_Param:
case Script_SRelative:
case Script_Property:
case Script_Offset:
if (opsize)
param_value = data [seeker++];
else {
param_value = 0xffff & (data[seeker] | (data[seeker+1] << 8));
seeker += 2;
}
if (pass_no == 1) {
if (opcode == op_jmp || opcode == op_bt || opcode == op_bnt) {
dest = seeker + (short) param_value;
sprintf(buf, "lbl_%04X", dest);
script_add_name(s, dest, buf, -2);
}
} else if (pass_no == 2)
switch (formats[opcode][i]) {
case Script_SVariable:
case Script_Variable:
if (opcode == op_callk) {
sciprintf(" #%s", (param_value < d->kernel_names_nr)
? d->kernel_names[param_value] : "<invalid>");
if (verbose) sciprintf("[%x]", param_value);
} else if (opcode == op_class || (opcode == op_super && i == 0)) {
sciprintf(" %s", (d->class_names && param_value < d->class_count)
? d->class_names[param_value] : "<invalid>");
if (verbose) sciprintf("[%x]", param_value);
} else sciprintf(opsize ? " %02x" : " %04x", param_value);
if (opcode == op_pushi && param_value > 0 && param_value < d->selector_count)
sciprintf("\t\t; selector <%s>", d->snames [param_value]);
break;
case Script_Global:
sciprintf(" global_%d", param_value);
break;
case Script_Local:
sciprintf(" local_%d", param_value);
break;
case Script_Temp:
sciprintf(" temp_%d", param_value);
break;
case Script_Param:
sciprintf(" param_%d", param_value);
break;
case Script_Offset:
dest = (short) param_value;
dest_name = script_find_name(s, dest, NULL);
if (dest_name)
sciprintf(" %s", dest_name);
else
sciprintf(" %04x", dest);
if (verbose)
sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value);
if (opcode == op_lofsa || opcode == op_lofss) {
int atype = script_get_area_type(s, dest, &area_data);
if (atype == area_string) {
strncpy(buf, (char *) &data [dest], sizeof(buf) - 1);
buf [sizeof(buf)-1] = 0;
if (strlen(buf) > 40) {
buf [40] = 0;
strcat(buf, "...");
}
sciprintf("\t\t; \"%s\"", buf);
} else if (atype == area_said) {
sciprintf("\t\t; said \"");
script_dump_said_string(d, data, dest);
sciprintf("\"\n");
} else if (atype == area_object)
sciprintf("\t\t; object <%s>", area_data);
}
break;
case Script_SRelative:
dest = seeker + (short) param_value;
dest_name = script_find_name(s, dest, NULL);
if (dest_name)
sciprintf(" %s", dest_name);
else
sciprintf(" %04x", dest);
if (verbose)
sciprintf(opsize ? " [%02x] " : " [%04x] ", param_value);
if (opcode == op_lofsa || opcode == op_lofss) {
int atype = script_get_area_type(s, dest, &area_data);
if (atype == area_string) {
strncpy(buf, (char *) &data [dest], sizeof(buf) - 1);
buf [sizeof(buf)-1] = 0;
if (strlen(buf) > 40) {
buf [40] = 0;
strcat(buf, "...");
}
sciprintf("\t\t; \"%s\"", buf);
} else if (atype == area_said) {
sciprintf("\t\t; said \"");
script_dump_said_string(d, data, dest);
sciprintf("\"\n");
} else if (atype == area_object)
sciprintf("\t\t; object <%s>", area_data);
}
break;
case Script_Property:
if (cur_class != -1 && param_value / 2 < d->class_selector_count [cur_class]) {
sciprintf(" %s", get_selector_name(d, d->class_selectors [cur_class][param_value/2]));
if (verbose) sciprintf("[%x]", param_value);
} else
sciprintf(opsize ? " %02x" : " %04x", param_value);
break;
case Script_End:
if (pass_no == 2) sciprintf("\n");
break;
default:
sciprintf("Unexpected opcode format %d\n", (formats[opcode][i]));
}
default:
break;
}
if (pass_no == 2) sciprintf("\n");
}
}
void
disassemble_script_pass(disasm_state_t *d, script_state_t *s,
resource_t *script, int pass_no) {
int _seeker = 0;
word id = getInt16(script->data);
if (id > 15) {
if (pass_no == 2) sciprintf("; Old script header detected\n");
d->old_header = 1;
}
if (d->old_header) _seeker = 2;
while (_seeker < script->size) {
int objtype = getInt16(script->data + _seeker);
int objsize;
int seeker = _seeker + 4;
if (!objtype) return;
if (pass_no == 2)
sciprintf("\n");
objsize = getInt16(script->data + _seeker + 2);
if (pass_no == 2) {
sciprintf("; Obj type #%x, offset 0x%x, size 0x%x:\n", objtype, _seeker, objsize);
if (hexdump) sci_hexdump(script->data + seeker, objsize - 4, seeker);
}
_seeker += objsize;
switch (objtype) {
case sci_obj_object:
script_dump_object(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_code:
script_disassemble_code(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_synonyms:
script_dump_synonyms(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_said:
script_dump_said(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_strings:
script_dump_strings(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_class:
script_dump_class(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_exports:
script_dump_exports(d, s, script->data, seeker, objsize, pass_no);
break;
case sci_obj_pointers:
if (pass_no == 2) {
sciprintf("Pointers\n");
sci_hexdump(script->data + seeker, objsize - 4, seeker);
};
break;
case sci_obj_preload_text:
if (pass_no == 2) {
sciprintf("The script has a preloaded text resource\n");
};
break;
case sci_obj_localvars:
if (pass_no == 2) {
sciprintf("Local vars\n");
sci_hexdump(script->data + seeker, objsize - 4, seeker);
};
break;
default:
sciprintf("Unsupported %d!\n", objtype);
return;
}
}
sciprintf("Script ends without terminator\n");
}
void
disassemble_script(disasm_state_t *d, int res_no, int pass_no) {
resource_t *script = scir_find_resource(resmgr, sci_script, res_no, 0);
script_state_t *s = find_script_state(d, res_no);
if (!script) {
sciprintf("Script not found!\n");
return;
}
disassemble_script_pass(d, s, script, pass_no);
}

View File

@@ -0,0 +1,45 @@
# LSL2 per-resource palette configuration
# Copyright (C) 2006 Matt Hargett
gameid = LSL2;
#ego
view(507,155,161,163,170,197,198,431,432,145..159,131..141,191,104,244,215,217,219,100,101,110,111,112,113,192,193,604,704..706,717,718,818,819,822,823,824,831,832,833,834,835) *= 1.25;
pic(28,99) *= 1.25;
view(218)(3) *= 1.25;
view(218)(0..2) *= 0.9;
view(820)(0,1) *= 0.9;
view(227,224,206,208,209,220) *= 0.9;
view(221,254,252) *= 0.7;
view(820)(2..4) *= 1.2;
view(816)(5)(0) *= 1.2;
view(516,509,501..504,401..403,408,409,411,413,414,417,418,419,430,310,302,303,120..124,232,223,208,710,716,714) *=1.1;
view(434..438,311,313,316,319,321,323,324,306..309,248,245,246,233..235,237,226,229,222,203,204,205,600,525,524,523,522,520,602,605,608,707..708) *=1.2;
view(305)(4) *= 1.1;
view(305)(0..3) *= 0.6;
view(661)(0,1,3..5) *= 1.2;
view(661)(2) *= 0.7;
view(711,712,713,60) *= (0.9, 1.0, 1.0);
view(816)(0..4) *= 0.9;
view(506,508,500,252,803,804,433) *= 0.6;
view(513)(0..5) *= 0.5;
view(240..243,701,722) *= 0.8;
view(700)(1) *= (0.6, 0.9, 1.0);
view(610,611) *= (0.9, 1.0, 1.1);
view(607)(1) *= 0.8;
view(253,228,247,300,326) *= 0.8;
view(412) *= 1.3;
pic(96) *= 1.1;
pic(92,93,18,20..26,134,40,50,76..82,181) *= 0.9;
pic(114..118,125,11..17,19,43,70..74,44,86,101..104,32,33,35,36,95) *= 0.85;
#titles
view(800,801) *= 1.5;
pic(10,90,91) *= 0.4;
#misc effects
view(702) *= (1.1, 1.0, 1.0);
view(519) *= 0.8;
view(200)(0) *= 0.7;
view(201,202) *= 0.8;

View File

@@ -0,0 +1,232 @@
from __future__ import print_function
import sys
from typing import List, Tuple, Any
def Chunker(seq: List[Any], size: int) -> List[List[Any]]:
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
def ModToIndex(mods: List[Tuple[int]], m: int):
try:
return mods.index(m)
except ValueError:
mods.append(m)
return len(mods)-1
def PrintMods(gid: str, mods: List[Tuple[int]]):
L = [ "\t{ " + ", ".join( [ "%4d" % (round(128 * (val - 1)),) for val in m ] ) + " }" for m in mods ]
print("static const PaletteMod paletteMods" + gid + "[] = {")
print( ",\n".join(L) )
print("};")
def PrintPic(gid: str, pics: List[List[int]], comments: List[str]):
print("static const PicMod picMods" + gid + "[] = {")
for comment in comments:
print("\t// " + comment)
for chunk in Chunker(pics, 5):
t = ""
for pic in chunk:
t = t + "{ " + str(pic[0]).rjust(3, ' ') + ", " + str(pic[1]).rjust(2, ' ') + " }, "
print("\t" + t)
print("};")
def PrintView(gid: str, views: List[List[int]], comments: List[str]):
print("static const ViewMod viewMods" + gid + "[] = {")
for comment in comments:
print("\t// " + comment)
for chunk in Chunker(views, 5):
t = ""
for view in chunk:
t = t + "{ " + str(view[0]).rjust(3, ' ') + ", " + str(view[1]).rjust(2, ' ') + ", " + str(view[2]).rjust(2, ' ') + ", " + str(view[3]).rjust(2, ' ') + " }, "
print("\t" + t)
print("};")
def ParseList(l: str) -> Tuple[str, List[str]]:
assert(l[0] == '(')
e = l.find(")")
L = l[1:e].split(",")
tests = []
for t in L:
t = t.strip()
ell = t.find('..')
if ell >= 0:
start = int(t[0:ell])
end = int(t[ell+2:])
# interval
for x in range(start, end + 1):
tests.append(str(x))
else:
tests.append(t)
return l[e+1:], tests
def ParseTriple(l: str) -> List[str]:
assert(l[0] == '(')
e = l.find(")")
L = l[1:e].split(",")
assert(len(L) == 3)
return L
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python scifx_to_header.py [scifx files] > scifx.cpp")
sys.exit(-1)
print("""
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
// NB: This file is AUTO-GENERATED by devtools/sci/scifx/scifx_to_cpp.py
// from devtools/sci/scifx/*.scifx
#include "sci/graphics/helpers.h"
#include "sci/graphics/screen.h"
namespace Sci {
""")
input_files = sys.argv[1:]
gids = []
for F in input_files:
comments = []
pics = []
views = []
mods = [(1.,1.,1.)]
gid = ""
for l in open(F, "r").readlines():
l = l.strip()
if len(l) == 0:
continue
if l[0] == '#':
comment = l[1:].strip()
# Only add the top comments (before the game ID is set)
if (gid == ""):
comments.append(comment)
continue
if l[0:6] == "gameid":
assert(gid == "")
l = l[6:].strip()
l = l.strip()
assert(l[0] == "=")
assert(l[-1] == ";")
l = l[1:-1].strip()
gid = l
continue
if l[0:4] == "view":
ruletype = "view"
l = l[4:]
elif l[0:3] == "pic":
ruletype = "pic"
l = l[3:]
else:
assert(False)
ids = []
loops = [-1]
cels = [-1]
l,ids = ParseList(l)
if l[0] == "(":
l,loops = ParseList(l)
if l[0] == "(":
l,cels = ParseList(l)
l = l.strip()
assert(l[0:2] == "*=")
assert(l[-1] == ";")
l = l[2:-1].strip()
if l[0] == "(":
val = ParseTriple(l)
val = (float(v) for v in val)
else:
val = (float(l), float(l), float(l))
if ruletype == "pic":
for pic in ids:
pics.append([pic, ModToIndex(mods, val)])
elif ruletype == "view":
for view in ids:
for loop in loops:
for cel in cels:
views.append([view, loop, cel, ModToIndex(mods, val)])
if gid == "":
raise ValueError("No gameid specified")
gids.append(gid)
PrintMods(gid, mods)
print()
PrintPic(gid, pics, comments)
print()
PrintView(gid, views, comments)
print()
print("static const SciFxMod mods[] = {")
for gid in gids:
print("\t{{ gid_{0}, paletteMods{0}, ARRAYSIZE(paletteMods{0}), picMods{0}, ARRAYSIZE(picMods{0}), viewMods{0}, ARRAYSIZE(viewMods{0}) }},".format(gid));
print("};")
print("""
void setupCustomPaletteMods(GfxScreen *screen) {
for (int i = 0; i < ARRAYSIZE(mods); i++) {
if (mods[i].gameId == g_sci->getGameId()) {
screen->setPaletteMods(mods[i].paletteMods, mods[i].paletteModsSize);
break;
}
}
}
void doCustomViewPalette(GfxScreen *screen, GuiResourceId view, int16 loop, int16 cel) {
for (int i = 0; i < ARRAYSIZE(mods); i++) {
SciFxMod mod = mods[i];
if (mod.gameId == g_sci->getGameId()) {
for (int j = 0; j < mod.viewModsSize; j++) {
ViewMod m = mod.viewMods[j];
if (m.id == view && (m.loop == -1 || m.loop == loop) && (m.cel == -1 || m.cel == cel)) {
screen->setCurPaletteMapValue(m.multiplier);
break;
}
}
break;
}
}
}
void doCustomPicPalette(GfxScreen *screen, GuiResourceId pic) {
for (int i = 0; i < ARRAYSIZE(mods); i++) {
SciFxMod mod = mods[i];
if (mod.gameId == g_sci->getGameId()) {
for (int j = 0; j < mod.picModsSize; j++) {
PicMod m = mod.picMods[j];
if (m.id == pic) {
screen->setCurPaletteMapValue(m.multiplier);
break;
}
}
break;
}
}
}
}""")

View File

@@ -0,0 +1,83 @@
# SQ3 per-resource palette configuration
# Copyright (C) 2006 Matt Hargett
gameid = SQ3;
# ego
view(0,8,11,12,14,68,17,22..26,32,35, 751, 289, 288, 261, 260, 257, 213, 199, 193, 192, 138, 137, 134, 109, 110, 113, 114, 117, 122, 123,100, 99, 97, 95, 89, 88, 87, 85, 84, 82, 76, 68, 63, 104 ) *= 1.25 ;
view(136) *= 1.15;
view(106)(4,5,9) *= 1.25;
view(105)(0,1) *= 1.25;
# ego on garbage lifter -- lighten but not so as to make the lifter be obviously weird
view(13)(0)(2) *= 1.15 ;
view(31) *= 1.15;
view(15)(3)(0) *= 1.25 ;
view(16,19)(0) *= 1.25;
view(57)(5..6) *= 1.25 ;
view(21)(1) *= 1.25 ;
# ego's shadow
view(7,18) *= 0.5;
view(6..8,18) *= 0.9;
view(901) *= 1.25;
view(751) *= 1.25;
view(750)(1) *= 1.25;
view(92)(4) *= 1.25;
view(83)(0) *= 1.25;
view(83)(1)(2) *=1.15;
view(83)(2)(2) *=1.15;
view(78)(3) *= 1.25;
view(64)(2,3) *= 1.25;
# ego's hands controlling robot
pic(96) *= 1.15;
# peeking at scumsoft
pic(81,82) *= 1.15;
#lifted by robot
pic(430) *= 1.15;
# computer controls
view(40,41,42,149,146,141,151,152) *= 0.8;
view(70,2) *= 0.9;
pic(17,18,162..164,170,180,191,300) *= 0.75;
# title screen
view(900) *= 0.9;
pic(1) *= 0.9 ;
pic(926) *= 0.9;
# humans(?)
view(593,93,103,131..133,210,130,115) *= 1.2;
pic(117) *=1.15;
view(116)(1..2) *= 1.2;
#ships, planets, and robots
view(39) *= 0.9;
view(1) *= 0.75;
pic(205..209,112..115) *= 0.9;
pic(60..72) *= 0.9;
pic(153) *= 0.8;
view(96) *= 0.9;
pic(690) *= 0.9;
view(77)(0..2) *= 0.7;
view(259) *= 1.15;
# in the garbage scow
pic(1..20) *= 0.75 ;
pic(157) *= 0.6;
view(20)(0) *= 0.5;
# rats
view(15)(0,1) *= 0.6;
view(34) *= 0.6;
# guys from andromeda
view(128) *= 0.9;
view(601, 602) *= 0.9;
# misc text bubbles, effects, etc
view(94) *= 1.1;
view(91, 73) *= 1.5;
view(57)(3,4) *= 1.5;
view(15)(4) *= 1.5;
view(64)(0) *= 1.5;
view(71)(8) *= 1.5;
view(10)(6) *= 1.5;

204
devtools/sci/scipack.cpp Normal file
View File

@@ -0,0 +1,204 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sciresource.h>
#include <resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#define COPY_BLOCK_SIZE 512
unsigned short *resource_ids = NULL;
void
help() {
printf("Usage:\n\tscipack <file_0> ... <file_n>\n"
"\nBuilds an uncompressed SCI0 resource.000 and a resource.map\n");
}
int /* Returns resource ID on success, -1 on error */
test_file(char *filename) {
char *dot = strchr(filename, '.');
char *endptr;
FILE *f;
int res_type, res_index;
if (!dot) {
fprintf(stderr, "Must contain a period");
return -1;
}
*dot = 0;
for (res_type = 0; res_type < sci_invalid_resource
&& scumm_stricmp(filename, sci_resource_types[res_type]); res_type++);
*dot = '.';
if (res_type == sci_invalid_resource) {
fprintf(stderr, "Invalid resource type");
return -1;
}
++dot;
res_index = strtol(dot, &endptr, 10);
if (!*dot || *endptr) {
fprintf(stderr, "Invalid resource index");
return -1;
}
if (res_index < 0) {
fprintf(stderr, "Negative resource index");
return -1;
}
if (res_index >= 1000) {
fprintf(stderr, "Resource index too large");
return -1;
}
f = fopen(filename, "r");
if (!f) {
perror("While asserting file");
return -1;
}
fclose(f);
return (res_type << 11) | res_index;
}
int
build_file_ids(int count, char **names) {
int i;
int error = 0;
resource_ids = (unsigned short*) malloc(sizeof(unsigned short) * count);
for (i = 0; i < count; i++) {
int id = test_file(names[i]);
if (id < 0) {
error = -1;
fprintf(stderr, ": %s\n", names[i]);
} else resource_ids[i] = id;
}
return error;
}
static inline void
write_uint16(int fd, unsigned int uint) {
unsigned char upper = (uint >> 8) & 0xff;
unsigned char lower = (uint) & 0xff;
if ((write(fd, &upper, 1) < 1)
|| (write(fd, &lower, 1) < 1)) {
perror("While writing");
exit(1);
}
}
int
write_files(int count, char **names) {
int resource_000, resource_map;
int i;
resource_000 = creat("resource.000", 0644);
if (resource_000 < 0) {
perror("While creating 'resource.000'");
return -1;
}
resource_map = creat("resource.map", 0644);
if (resource_map < 0) {
perror("While creating 'resource.map'");
return -1;
}
for (i = 0; i < count; i++) {
int fd = open(names[i], O_RDONLY);
struct stat fdstat;
int fdsize;
unsigned char buf[512];
int j;
long offset = lseek(resource_000, SEEK_CUR, 0);
int top_offset = (offset >> 16) & 0xffff;
int bot_offset = offset & 0xffff;
if (fd < 0) {
perror(names[i]);
return -1;
}
fstat(fd, &fdstat);
fdsize = fdstat.st_size;
write_uint16(resource_000, resource_ids[i]);
write_uint16(resource_000, fdsize);
write_uint16(resource_000, fdsize);
write_uint16(resource_000, 0);
do {
j = read(fd, buf, COPY_BLOCK_SIZE);
write(resource_000, buf, j);
} while (j == COPY_BLOCK_SIZE);
close(fd);
write_uint16(resource_map, resource_ids[i]);
write_uint16(resource_map, bot_offset);
write_uint16(resource_map, top_offset);
}
/* Terminate resource 000 */
write_uint16(resource_000, 0);
/* Terminate resource map */
write_uint16(resource_map, 0xffff);
write_uint16(resource_map, 0xffff);
close(resource_000);
close(resource_map);
}
int
main(int argc, char **argv) {
printf("scipack.c Copyright (C) 2002 Christoph Reichenbach\n"
"This program is FREE SOFTWARE. You may copy it and/or re-distribute it\n"
"according to the terms of the GNU General Public License. See LICENSING\n"
"for details.\n");
if (argc < 1)
help();
if (build_file_ids(argc - 1, argv + 1))
return -1;
if (write_files(argc - 1, argv + 1))
return -1;
free(resource_ids);
}

131
devtools/sci/scitrace.asm Normal file
View File

@@ -0,0 +1,131 @@
; 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 3 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, see <http://www.gnu.org/licenses/>.
;
;---------------------------------------------------------------------------
;
; SCITRACE
; TSR for logging specific calls inside sierra sci
; Written by M. Kiewitz
;
;---------------------------------------------------------------------------
; Simply replace 51h 51h 51h 51h in sierra sci with
; CDh 90h 90h 90h. This code will then log copyrect calls to scitrace.bin
.286
code_seg segment public
assume cs:code_seg, ds:nothing, es:nothing
org 00100h
scitrace: jmp install_my_prog
;---------------------------------------------------------------------------
filename: db 'SCITRACE.BIN', 0
inthandler: push ax
push bx
push cx
push dx
push ds
push cs
pop ds
mov ah, 3Dh
mov al, 1
mov dx, offset filename
xor cl, cl
int 21h
pop ds
jc int_error
mov bx, ax
mov ax, 4202h
xor cx, cx
xor dx, dx
int 21h
mov dx, si
mov ah, 40h
mov cx, 8
int 21h
mov ah, 3Eh
int 21h
int_error: pop dx
pop cx
pop bx
pop ax
movsw
movsw
movsw
movsw
iret
end_of_tsr:
;---------------------------------------------------------------------------
titlestr: db 'SCITRACE - written by M. Kiewitz',13,10,'$'
errorfile: db 'error creating file',13,10,'$'
;---------------------------------------------------------------------------
install_my_prog:
push cs
pop ds
mov ah, 09h
mov dx, offset titlestr
int 21h
mov ah, 3Ch
mov cx, 0
mov dx, offset filename
int 21h
jnc valid_open
mov ah, 09h
mov dx, offset errorfile
int 21h
mov ax, 6200h
int 21h
mov es, bx
mov ax, 4C00h
int 21h
valid_open: mov bx, ax
mov ah, 3Eh
int 21h
NowInstallTSR:
mov ax, 2590h
mov dx, offset inthandler
int 21h ; int 90h pointer <- ds:dx
mov ax, ds:[002ch] ; get envt segment
mov es, ax
mov ax, 4900h
int 21h
mov dx, offset end_of_tsr
add dx, 15
shr dx, 4
mov ax, 3100h
int 21h
;---------------------------------------------------------------------------
code_seg ends
end scitrace