/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers Copyright (C) 2019 Alison G. Watson 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_defs.h" ddef_t *pr_globaldefs; cvar_t nomonsters = {"nomonsters", "0", CVAR_NONE}; cvar_t gamecfg = {"gamecfg", "0", CVAR_NONE}; cvar_t scratch1 = {"scratch1", "0", CVAR_NONE}; cvar_t scratch2 = {"scratch2", "0", CVAR_NONE}; cvar_t scratch3 = {"scratch3", "0", CVAR_NONE}; cvar_t scratch4 = {"scratch4", "0", CVAR_NONE}; cvar_t savedgamecfg = {"savedgamecfg", "0", CVAR_ARCHIVE}; cvar_t saved1 = {"saved1", "0", CVAR_ARCHIVE}; cvar_t saved2 = {"saved2", "0", CVAR_ARCHIVE}; cvar_t saved3 = {"saved3", "0", CVAR_ARCHIVE}; cvar_t saved4 = {"saved4", "0", CVAR_ARCHIVE}; static void PR_LoadProgHeader(byte const *data) { progs.version = ReadLittleLong(&data); progs.crc = ReadLittleLong(&data); progs.ofs_statements = ReadLittleLong(&data); progs.numstatements = ReadLittleLong(&data); progs.ofs_globaldefs = ReadLittleLong(&data); progs.numglobaldefs = ReadLittleLong(&data); progs.ofs_fielddefs = ReadLittleLong(&data); progs.numfielddefs = ReadLittleLong(&data); progs.ofs_functions = ReadLittleLong(&data); progs.numfunctions = ReadLittleLong(&data); progs.ofs_strings = ReadLittleLong(&data); progs.numstrings = ReadLittleLong(&data); progs.ofs_globals = ReadLittleLong(&data); progs.numglobals = ReadLittleLong(&data); progs.entityfields = ReadLittleLong(&data); /* round off to next highest whole word address (esp for Alpha) this ensures * that pointers in the engine data area are always properly aligned */ pr_edict_size = progs.entityfields * 4 + sizeof(edict_t); pr_edict_size += sizeof(void *) - 1; pr_edict_size &= ~(sizeof(void *) - 1); if(progs.version != PROG_VERSION) Host_Error("PR_LoadProgHeader: has wrong version number (%" PRIi32 " should be %" PRIi32 ")", progs.version, PROG_VERSION); if(progs.crc != PROGHEADER_CRC) Host_Error("PR_LoadProgHeader: system vars are modified\n"); if(progs.ofs_strings + progs.numstrings >= com_filesize) Host_Error("PR_LoadProgHeader: strings go past end of file\n"); if(progs.numglobals < GBL_SYSTEM_END) Host_Error("PR_LoadProgHeader: not enough globals\n"); if(progs.entityfields < ED_SYSTEM_END) Host_Error("PR_LoadProgHeader: not enough entity fields\n"); } static void PR_LoadFunctions(byte const *data) { int32_t i; pr_functions = Hunk_AllocName(sizeof(*pr_functions) * progs.numfunctions, "pr_functions"); for(i = 0; i < progs.numfunctions; i++) { dfunction_t *fn = &pr_functions[i]; fn->first_statement = ReadLittleLong(&data); fn->parm_start = ReadLittleLong(&data); fn->locals = ReadLittleLong(&data); fn->profile = 0; ReadSkip(&data, 4); fn->s_name = ReadLittleLong(&data); fn->s_file = ReadLittleLong(&data); fn->numparms = ReadLittleLong(&data); ReadCopy(fn->parm_size, &data, 8); } } static void PR_LoadStrings(byte const *data) { pr_strings = Hunk_Memdup(data, progs.numstrings, "pr_strings"); // initialize the strings pr_numknownstrings = 0; pr_maxknownstrings = 0; if(pr_knownstrings) Z_Free(pr_knownstrings); pr_knownstrings = NULL; PR_SetEngineString(""); } static void PR_LoadDef(ddef_t *def, byte const **data) { def->type = ReadLittleShort(data); def->ofs = ReadLittleShort(data); def->s_name = ReadLittleLong(data); } static void PR_LoadGlobalDefs(byte const *data) { int32_t i; pr_globaldefs = Hunk_AllocName(sizeof(*pr_globaldefs) * progs.numglobaldefs, "pr_globaldefs"); for(i = 0; i < progs.numglobaldefs; i++) { PR_LoadDef(&pr_globaldefs[i], &data); } } static void PR_LoadFieldDefs(byte const *data) { int32_t i; pr_fielddefs = Hunk_AllocName(sizeof(*pr_fielddefs) * progs.numfielddefs, "pr_fielddefs"); pr_alpha_supported = false; //johnfitz for(i = 0; i < progs.numfielddefs; i++) { ddef_t *def = &pr_fielddefs[i]; PR_LoadDef(def, &data); if(def->type & DEF_SAVEGLOBAL) Host_Error("PR_LoadProgs: field defs cannot have DEF_SAVEGLOBAL"); //johnfitz -- detect alpha support if(!strcmp(&pr_strings[def->s_name], "alpha")) pr_alpha_supported = true; //johnfitz } } static void PR_LoadStatements(byte const *data) { int32_t i; pr_statements = Hunk_AllocName(sizeof(*pr_statements) * progs.numstatements, "pr_statements"); for(i = 0; i < progs.numstatements; i++) { dstatement_t *st = &pr_statements[i]; st->op = ReadLittleShort(&data); st->a = ReadLittleShort(&data); st->b = ReadLittleShort(&data); st->c = ReadLittleShort(&data); if(st->op >= OP_MAX) Host_Error("PR_LoadStatements: bad opcode %" PRIi32, st->op); } } static void PR_LoadGlobals(byte const *data) { int32_t i; pr_global_data = Hunk_Memdup(data, progs.numglobals * 4, "pr_global_data"); for(i = 0; i < progs.numglobals; i++) G_Int(i) = LittleLong(G_Int(i)); } /* =============== PR_LoadProgs =============== */ void PR_LoadProgs(void) { byte *prog_data; int32_t i; ED_Load(); CRC_Init(&pr_crc); prog_data = COM_LoadTempFile("progs.dat", NULL); if(!prog_data) Host_Error("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf("Programs occupy %" PRIi32 "K\n", com_filesize / 1024); for(i = 0; i < com_filesize; i++) CRC_ProcessByte(&pr_crc, prog_data[i]); PR_LoadProgHeader(prog_data); PR_LoadStrings(&prog_data[progs.ofs_strings]); PR_LoadStatements(&prog_data[progs.ofs_statements]); PR_LoadFunctions(&prog_data[progs.ofs_functions]); PR_LoadGlobalDefs(&prog_data[progs.ofs_globaldefs]); PR_LoadFieldDefs(&prog_data[progs.ofs_fielddefs]); PR_LoadGlobals(&prog_data[progs.ofs_globals]); } /* =============== PR_Init =============== */ void PR_Init(void) { ED_Init(); Cmd_AddCommand("profile", PR_Profile_f); Cvar_RegisterVariable(&nomonsters); Cvar_RegisterVariable(&gamecfg); Cvar_RegisterVariable(&scratch1); Cvar_RegisterVariable(&scratch2); Cvar_RegisterVariable(&scratch3); Cvar_RegisterVariable(&scratch4); Cvar_RegisterVariable(&savedgamecfg); Cvar_RegisterVariable(&saved1); Cvar_RegisterVariable(&saved2); Cvar_RegisterVariable(&saved3); Cvar_RegisterVariable(&saved4); }