/*
- * Copyright (C) 2012, 2013, 2014
+ * Copyright (C) 2012, 2013, 2014, 2015
* Wolfgang Bumiller
* Dale Weiler
*
{
prog_header_t header;
qc_program_t *prog;
- fs_file_t *file = fs_file_open(filename, "rb");
+ size_t i;
+ FILE *file = fopen(filename, "rb");
+
+ /* we need all those in order to support INSTR_STATE: */
+ bool has_self = false,
+ has_time = false,
+ has_think = false,
+ has_nextthink = false,
+ has_frame = false;
if (!file)
return NULL;
- if (fs_file_read(&header, sizeof(header), 1, file) != 1) {
+ if (fread(&header, sizeof(header), 1, file) != 1) {
loaderror("failed to read header from '%s'", filename);
- fs_file_close(file);
+ fclose(file);
return NULL;
}
if (!skipversion && header.version != 6) {
loaderror("header says this is a version %i progs, we need version 6\n", header.version);
- fs_file_close(file);
+ fclose(file);
return NULL;
}
prog = (qc_program_t*)mem_a(sizeof(qc_program_t));
if (!prog) {
- fs_file_close(file);
+ fclose(file);
fprintf(stderr, "failed to allocate program data\n");
return NULL;
}
}
#define read_data(hdrvar, progvar, reserved) \
- if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
+ if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
loaderror("seek failed"); \
goto error; \
} \
- if (fs_file_read ( \
+ if (fread( \
vec_add(prog->progvar, header.hdrvar.length + reserved), \
sizeof(*prog->progvar), \
header.hdrvar.length, \
util_swap_functions (prog->functions);
util_swap_globals (prog->globals);
- fs_file_close(file);
+ fclose(file);
/* profile counters */
memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code));
memset(vec_add(prog->entitydata, prog->entityfields), 0, prog->entityfields * sizeof(prog->entitydata[0]));
prog->entities = 1;
+ /* cache some globals and fields from names */
+ for (i = 0; i < vec_size(prog->defs); ++i) {
+ const char *name = prog_getstring(prog, prog->defs[i].name);
+ if (!strcmp(name, "self")) {
+ prog->cached_globals.self = prog->defs[i].offset;
+ has_self = true;
+ }
+ else if (!strcmp(name, "time")) {
+ prog->cached_globals.time = prog->defs[i].offset;
+ has_time = true;
+ }
+ }
+ for (i = 0; i < vec_size(prog->fields); ++i) {
+ const char *name = prog_getstring(prog, prog->fields[i].name);
+ if (!strcmp(name, "think")) {
+ prog->cached_fields.think = prog->fields[i].offset;
+ has_think = true;
+ }
+ else if (!strcmp(name, "nextthink")) {
+ prog->cached_fields.nextthink = prog->fields[i].offset;
+ has_nextthink = true;
+ }
+ else if (!strcmp(name, "frame")) {
+ prog->cached_fields.frame = prog->fields[i].offset;
+ has_frame = true;
+ }
+ }
+ if (has_self && has_time && has_think && has_nextthink && has_frame)
+ prog->supports_state = true;
+
return prog;
error:
vec_free(prog->entitypool);
mem_d(prog);
- fs_file_close(file);
+ fclose(file);
return NULL;
}
done:
if (len < (int)sizeof(spaces)-1) {
spaces[sizeof(spaces)-1-len] = 0;
- fs_file_puts((fs_file_t*)stdout, spaces);
+ fputs(spaces, stdout);
spaces[sizeof(spaces)-1-len] = ' ';
}
}
break;
case INSTR_STATE:
- qcvmerror(prog, "`%s` tried to execute a STATE operation", prog->filename);
+ {
+ qcfloat_t *nextthink;
+ qcfloat_t *time;
+ qcfloat_t *frame;
+ if (!prog->supports_state) {
+ qcvmerror(prog, "`%s` tried to execute a STATE operation but misses its defs!", prog->filename);
+ goto cleanup;
+ }
+ ed = prog_getedict(prog, prog->globals[prog->cached_globals.self]);
+ ((qcint_t*)ed)[prog->cached_fields.think] = OPB->function;
+
+ frame = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.frame];
+ *frame = OPA->_float;
+ nextthink = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.nextthink];
+ time = (qcfloat_t*)(prog->globals + prog->cached_globals.time);
+ *nextthink = *time + 0.1;
break;
+ }
case INSTR_GOTO:
st += st->o1.s1 - 1; /* offset the s++ */