+void SV_VM_CB_InitEdict(prvm_edict_t *e)
+{
+ // LordHavoc: for consistency set these here
+ int num = PRVM_NUM_FOR_EDICT(e) - 1;
+
+ if (num >= 0 && num < svs.maxclients)
+ {
+ prvm_eval_t *val;
+ // set colormap and team on newly created player entity
+ e->fields.server->colormap = num + 1;
+ e->fields.server->team = (svs.clients[num].colors & 15) + 1;
+ // set netname/clientcolors back to client values so that
+ // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
+ // reset them
+ e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
+ if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
+ val->_float = svs.clients[num].colors;
+ // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
+ if( eval_playermodel )
+ PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
+ if( eval_playerskin )
+ PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+ }
+}
+
+void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
+{
+ SV_UnlinkEdict (ed); // unlink from world bsp
+
+ ed->fields.server->model = 0;
+ ed->fields.server->takedamage = 0;
+ ed->fields.server->modelindex = 0;
+ ed->fields.server->colormap = 0;
+ ed->fields.server->skin = 0;
+ ed->fields.server->frame = 0;
+ VectorClear(ed->fields.server->origin);
+ VectorClear(ed->fields.server->angles);
+ ed->fields.server->nextthink = -1;
+ ed->fields.server->solid = 0;
+}
+
+void SV_VM_CB_CountEdicts(void)
+{
+ int i;
+ prvm_edict_t *ent;
+ int active, models, solid, step;
+
+ active = models = solid = step = 0;
+ for (i=0 ; i<prog->num_edicts ; i++)
+ {
+ ent = PRVM_EDICT_NUM(i);
+ if (ent->priv.server->free)
+ continue;
+ active++;
+ if (ent->fields.server->solid)
+ solid++;
+ if (ent->fields.server->model)
+ models++;
+ if (ent->fields.server->movetype == MOVETYPE_STEP)
+ step++;
+ }
+
+ Con_Printf("num_edicts:%3i\n", prog->num_edicts);
+ Con_Printf("active :%3i\n", active);
+ Con_Printf("view :%3i\n", models);
+ Con_Printf("touch :%3i\n", solid);
+ Con_Printf("step :%3i\n", step);
+}
+
+qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
+{
+ // remove things from different skill levels or deathmatch
+ if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
+ {
+ if (deathmatch.integer)
+ {
+ if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
+ {
+ return false;
+ }
+ }
+ else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
+ || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
+ || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1"};
+cvar_t nomonsters = {0, "nomonsters", "0"};
+cvar_t gamecfg = {0, "gamecfg", "0"};
+cvar_t scratch1 = {0, "scratch1", "0"};
+cvar_t scratch2 = {0,"scratch2", "0"};
+cvar_t scratch3 = {0, "scratch3", "0"};
+cvar_t scratch4 = {0, "scratch4", "0"};
+cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0"};
+cvar_t saved1 = {CVAR_SAVE, "saved1", "0"};
+cvar_t saved2 = {CVAR_SAVE, "saved2", "0"};
+cvar_t saved3 = {CVAR_SAVE, "saved3", "0"};
+cvar_t saved4 = {CVAR_SAVE, "saved4", "0"};
+cvar_t decors = {0, "decors", "0"};
+cvar_t nehx00 = {0, "nehx00", "0"};cvar_t nehx01 = {0, "nehx01", "0"};
+cvar_t nehx02 = {0, "nehx02", "0"};cvar_t nehx03 = {0, "nehx03", "0"};
+cvar_t nehx04 = {0, "nehx04", "0"};cvar_t nehx05 = {0, "nehx05", "0"};
+cvar_t nehx06 = {0, "nehx06", "0"};cvar_t nehx07 = {0, "nehx07", "0"};
+cvar_t nehx08 = {0, "nehx08", "0"};cvar_t nehx09 = {0, "nehx09", "0"};
+cvar_t nehx10 = {0, "nehx10", "0"};cvar_t nehx11 = {0, "nehx11", "0"};
+cvar_t nehx12 = {0, "nehx12", "0"};cvar_t nehx13 = {0, "nehx13", "0"};
+cvar_t nehx14 = {0, "nehx14", "0"};cvar_t nehx15 = {0, "nehx15", "0"};
+cvar_t nehx16 = {0, "nehx16", "0"};cvar_t nehx17 = {0, "nehx17", "0"};
+cvar_t nehx18 = {0, "nehx18", "0"};cvar_t nehx19 = {0, "nehx19", "0"};
+cvar_t cutscene = {0, "cutscene", "1"};
+
+void SV_VM_Init(void)
+{
+ Cvar_RegisterVariable (&pr_checkextension);
+ 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);
+ // LordHavoc: for DarkPlaces, this overrides the number of decors (shell casings, gibs, etc)
+ Cvar_RegisterVariable (&decors);
+ // LordHavoc: Nehahra uses these to pass data around cutscene demos
+ if (gamemode == GAME_NEHAHRA)
+ {
+ Cvar_RegisterVariable (&nehx00);Cvar_RegisterVariable (&nehx01);
+ Cvar_RegisterVariable (&nehx02);Cvar_RegisterVariable (&nehx03);
+ Cvar_RegisterVariable (&nehx04);Cvar_RegisterVariable (&nehx05);
+ Cvar_RegisterVariable (&nehx06);Cvar_RegisterVariable (&nehx07);
+ Cvar_RegisterVariable (&nehx08);Cvar_RegisterVariable (&nehx09);
+ Cvar_RegisterVariable (&nehx10);Cvar_RegisterVariable (&nehx11);
+ Cvar_RegisterVariable (&nehx12);Cvar_RegisterVariable (&nehx13);
+ Cvar_RegisterVariable (&nehx14);Cvar_RegisterVariable (&nehx15);
+ Cvar_RegisterVariable (&nehx16);Cvar_RegisterVariable (&nehx17);
+ Cvar_RegisterVariable (&nehx18);Cvar_RegisterVariable (&nehx19);
+ }
+ Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
+}
+
+// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
+int eval_gravity;
+int eval_button3;
+int eval_button4;
+int eval_button5;
+int eval_button6;
+int eval_button7;
+int eval_button8;
+int eval_buttonuse;
+int eval_buttonchat;
+int eval_glow_size;
+int eval_glow_trail;
+int eval_glow_color;
+int eval_items2;
+int eval_scale;
+int eval_alpha;
+int eval_renderamt; // HalfLife support
+int eval_rendermode; // HalfLife support
+int eval_fullbright;
+int eval_ammo_shells1;
+int eval_ammo_nails1;
+int eval_ammo_lava_nails;
+int eval_ammo_rockets1;
+int eval_ammo_multi_rockets;
+int eval_ammo_cells1;
+int eval_ammo_plasma;
+int eval_idealpitch;
+int eval_pitch_speed;
+int eval_viewmodelforclient;
+int eval_nodrawtoclient;
+int eval_exteriormodeltoclient;
+int eval_drawonlytoclient;
+int eval_ping;
+int eval_movement;
+int eval_pmodel;
+int eval_punchvector;
+int eval_viewzoom;
+int eval_clientcolors;
+int eval_tag_entity;
+int eval_tag_index;
+int eval_light_lev;
+int eval_color;
+int eval_style;
+int eval_pflags;
+int eval_cursor_active;
+int eval_cursor_screen;
+int eval_cursor_trace_start;
+int eval_cursor_trace_endpos;
+int eval_cursor_trace_ent;
+int eval_colormod;
+int eval_playermodel;
+int eval_playerskin;
+
+mfunction_t *SV_PlayerPhysicsQC;
+mfunction_t *EndFrameQC;
+//KrimZon - SERVER COMMANDS IN QUAKEC
+mfunction_t *SV_ParseClientCommandQC;
+
+void SV_VM_FindEdictFieldOffsets(void)
+{
+ eval_gravity = PRVM_ED_FindFieldOffset("gravity");
+ eval_button3 = PRVM_ED_FindFieldOffset("button3");
+ eval_button4 = PRVM_ED_FindFieldOffset("button4");
+ eval_button5 = PRVM_ED_FindFieldOffset("button5");
+ eval_button6 = PRVM_ED_FindFieldOffset("button6");
+ eval_button7 = PRVM_ED_FindFieldOffset("button7");
+ eval_button8 = PRVM_ED_FindFieldOffset("button8");
+ eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
+ eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
+ eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
+ eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
+ eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
+ eval_items2 = PRVM_ED_FindFieldOffset("items2");
+ eval_scale = PRVM_ED_FindFieldOffset("scale");
+ eval_alpha = PRVM_ED_FindFieldOffset("alpha");
+ eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
+ eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
+ eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
+ eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
+ eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
+ eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
+ eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
+ eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
+ eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
+ eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
+ eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
+ eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
+ eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
+ eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
+ eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
+ eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
+ eval_ping = PRVM_ED_FindFieldOffset("ping");
+ eval_movement = PRVM_ED_FindFieldOffset("movement");
+ eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
+ eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
+ eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
+ eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
+ eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
+ eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
+ eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
+ eval_color = PRVM_ED_FindFieldOffset("color");
+ eval_style = PRVM_ED_FindFieldOffset("style");
+ eval_pflags = PRVM_ED_FindFieldOffset("pflags");
+ eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
+ eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
+ eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
+ eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
+ eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
+ eval_colormod = PRVM_ED_FindFieldOffset("colormod");
+ eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
+ eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
+
+ // LordHavoc: allowing QuakeC to override the player movement code
+ SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
+ // LordHavoc: support for endframe
+ EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
+ //KrimZon - SERVER COMMANDS IN QUAKEC
+ SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
+}
+
+#define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
+
+prvm_required_field_t reqfields[] =
+{
+ {ev_entity, "cursor_trace_ent"},
+ {ev_entity, "drawonlytoclient"},
+ {ev_entity, "exteriormodeltoclient"},
+ {ev_entity, "nodrawtoclient"},
+ {ev_entity, "tag_entity"},
+ {ev_entity, "viewmodelforclient"},
+ {ev_float, "alpha"},
+ {ev_float, "ammo_cells1"},
+ {ev_float, "ammo_lava_nails"},
+ {ev_float, "ammo_multi_rockets"},
+ {ev_float, "ammo_nails1"},
+ {ev_float, "ammo_plasma"},
+ {ev_float, "ammo_rockets1"},
+ {ev_float, "ammo_shells1"},
+ {ev_float, "button3"},
+ {ev_float, "button4"},
+ {ev_float, "button5"},
+ {ev_float, "button6"},
+ {ev_float, "button7"},
+ {ev_float, "button8"},
+ {ev_float, "buttonchat"},
+ {ev_float, "buttonuse"},
+ {ev_float, "clientcolors"},
+ {ev_float, "cursor_active"},
+ {ev_float, "fullbright"},
+ {ev_float, "glow_color"},
+ {ev_float, "glow_size"},
+ {ev_float, "glow_trail"},
+ {ev_float, "gravity"},
+ {ev_float, "idealpitch"},
+ {ev_float, "items2"},
+ {ev_float, "light_lev"},
+ {ev_float, "pflags"},
+ {ev_float, "ping"},
+ {ev_float, "pitch_speed"},
+ {ev_float, "pmodel"},
+ {ev_float, "renderamt"}, // HalfLife support
+ {ev_float, "rendermode"}, // HalfLife support
+ {ev_float, "scale"},
+ {ev_float, "style"},
+ {ev_float, "tag_index"},
+ {ev_float, "viewzoom"},
+ {ev_vector, "color"},
+ {ev_vector, "colormod"},
+ {ev_vector, "cursor_screen"},
+ {ev_vector, "cursor_trace_endpos"},
+ {ev_vector, "cursor_trace_start"},
+ {ev_vector, "movement"},
+ {ev_vector, "punchvector"},
+ {ev_string, "playermodel"},
+ {ev_string, "playerskin"}
+};
+
+void SV_VM_Setup(void)
+{
+ PRVM_Begin;
+ PRVM_InitProg( PRVM_SERVERPROG );
+
+ // allocate the mempools
+ prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
+ prog->builtins = vm_sv_builtins;
+ prog->numbuiltins = vm_sv_numbuiltins;
+ prog->headercrc = PROGHEADER_CRC;
+ prog->max_edicts = 512;
+ prog->limit_edicts = MAX_EDICTS;
+ prog->reserved_edicts = svs.maxclients;
+ prog->edictprivate_size = sizeof(edict_engineprivate_t);
+ prog->name = "server";
+ prog->extensionstring = vm_sv_extensions;
+ prog->loadintoworld = true;
+
+ prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
+ prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
+ prog->init_edict = SV_VM_CB_InitEdict;
+ prog->free_edict = SV_VM_CB_FreeEdict;
+ prog->count_edicts = SV_VM_CB_CountEdicts;
+ prog->load_edict = SV_VM_CB_LoadEdict;
+ prog->init_cmd = VM_SV_Cmd_Init;
+ prog->reset_cmd = VM_SV_Cmd_Reset;
+ prog->error_cmd = Host_Error;
+
+ // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
+ PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
+ SV_VM_FindEdictFieldOffsets();
+
+ PRVM_End;
+}
+
+void SV_VM_Begin(void)
+{
+ PRVM_Begin;
+ PRVM_SetProg( PRVM_SERVERPROG );
+
+ *prog->time = (float) sv.time;
+}
+
+void SV_VM_End(void)
+{
+ PRVM_End;
+}