/// <summary> /// PF_walkmove /// float(float yaw, float dist) walkmove /// </summary> static void PF_walkmove() { edict_t ent = Server.ProgToEdict(Progs.GlobalStruct.self); float yaw = GetFloat(OFS.OFS_PARM0); float dist = GetFloat(OFS.OFS_PARM1); if (((int)ent.v.flags & (EdictFlags.FL_ONGROUND | EdictFlags.FL_FLY | EdictFlags.FL_SWIM)) == 0) { ReturnFloat(0); return; } yaw = (float)(yaw * Math.PI * 2.0 / 360.0); v3f move; move.x = (float)Math.Cos(yaw) * dist; move.y = (float)Math.Sin(yaw) * dist; move.z = 0; // save program state, because SV_movestep may call other progs dfunction_t oldf = Progs.xFunction; int oldself = Progs.GlobalStruct.self; ReturnFloat(Server.MoveStep(ent, ref move, true) ? 1 : 0); // restore program state Progs.xFunction = oldf; Progs.GlobalStruct.self = oldself; }
/// <summary> /// PR_LeaveFunction /// </summary> static int LeaveFunction() { if (_Depth <= 0) { Sys.Error("prog stack underflow"); } // restore locals from the stack int c = xFunction.locals; _LocalStackUsed -= c; if (_LocalStackUsed < 0) { RunError("PR_ExecuteProgram: locals stack underflow\n"); } for (int i = 0; i < c; i++) { Set(xFunction.parm_start + i, _LocalStack[_LocalStackUsed + i]); //((int*)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used + i]; } // up stack _Depth--; xFunction = _Stack[_Depth].f; return(_Stack[_Depth].s); }
// PR_Profile_f static void Profile_f() { if (_Functions == null) { return; } dfunction_t best; int num = 0; do { int max = 0; best = null; for (int i = 0; i < _Functions.Length; i++) { dfunction_t f = _Functions[i]; if (f.profile > max) { max = f.profile; best = f; } } if (best != null) { if (num < 10) { Con.Print("{0,7} {1}\n", best.profile, GetString(best.s_name)); } num++; best.profile = 0; } } while (best != null); }
/// <summary> /// PR_ValueString /// </summary> static unsafe string ValueString(etype_t type, void *val) { string result; type &= (etype_t) ~DEF_SAVEGLOBAL; switch (type) { case etype_t.ev_string: result = GetString(*(int *)val); break; case etype_t.ev_entity: result = "entity " + Server.NumForEdict(Server.ProgToEdict(*(int *)val)); break; case etype_t.ev_function: dfunction_t f = _Functions[*(int *)val]; result = GetString(f.s_name) + "()"; break; case etype_t.ev_field: ddef_t def = FindField(*(int *)val); result = "." + GetString(def.s_name); break; case etype_t.ev_void: result = "void"; break; case etype_t.ev_float: result = (*(float *)val).ToString("F1", CultureInfo.InvariantCulture.NumberFormat); break; case etype_t.ev_vector: result = String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0,5:F1} {1,5:F1} {2,5:F1}", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); break; case etype_t.ev_pointer: result = "pointer"; break; default: result = "bad type " + type.ToString(); break; } return(result); }
/// <summary> /// PR_UglyValueString /// Returns a string describing *data in a type specific manner /// Easier to parse than PR_ValueString /// </summary> static unsafe string UglyValueString(etype_t type, eval_t *val) { type &= (etype_t) ~DEF_SAVEGLOBAL; string result; switch (type) { case etype_t.ev_string: result = GetString(val->_string); break; case etype_t.ev_entity: result = Server.NumForEdict(Server.ProgToEdict(val->edict)).ToString(); break; case etype_t.ev_function: dfunction_t f = _Functions[val->function]; result = GetString(f.s_name); break; case etype_t.ev_field: ddef_t def = FindField(val->_int); result = GetString(def.s_name); break; case etype_t.ev_void: result = "void"; break; case etype_t.ev_float: result = val->_float.ToString("F6", CultureInfo.InvariantCulture.NumberFormat); break; case etype_t.ev_vector: result = String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:F6} {1:F6} {2:F6}", val->vector[0], val->vector[1], val->vector[2]); break; default: result = "bad type " + type.ToString(); break; } return(result); }
/// <summary> /// PR_EnterFunction /// Returns the new program statement counter /// </summary> static unsafe int EnterFunction(dfunction_t f) { _Stack[_Depth].s = _xStatement; _Stack[_Depth].f = xFunction; _Depth++; if (_Depth >= MAX_STACK_DEPTH) { RunError("stack overflow"); } // save off any locals that the new function steps on int c = f.locals; if (_LocalStackUsed + c > LOCALSTACK_SIZE) { RunError("PR_ExecuteProgram: locals stack overflow\n"); } for (int i = 0; i < c; i++) { _LocalStack[_LocalStackUsed + i] = *(int *)Get(f.parm_start + i); } _LocalStackUsed += c; // copy parameters int o = f.parm_start; for (int i = 0; i < f.numparms; i++) { for (int j = 0; j < f.parm_size[i]; j++) { Set(o, *(int *)Get(OFS.OFS_PARM0 + i * 3 + j)); o++; } } xFunction = f; return(f.first_statement - 1); // offset the s++ }
/// <summary> /// PR_StackTrace /// </summary> static void StackTrace() { if (_Depth == 0) { Con.Print("<NO STACK>\n"); return; } _Stack[_Depth].f = Progs.xFunction; for (int i = _Depth; i >= 0; i--) { dfunction_t f = _Stack[i].f; if (f == null) { Con.Print("<NO FUNCTION>\n"); } else { Con.Print("{0,12} : {1}\n", GetString(f.s_file), GetString(f.s_name)); } } }
/// <summary> /// PR_ExecuteProgram /// </summary> public unsafe static void Execute(int fnum) { if (fnum < 1 || fnum >= _Functions.Length) { if (Progs.GlobalStruct.self != 0) { Print(Server.ProgToEdict(Progs.GlobalStruct.self)); } Host.Error("PR_ExecuteProgram: NULL function"); } dfunction_t f = _Functions[fnum]; int runaway = 100000; Trace = false; // make a stack frame int exitdepth = _Depth; int ofs; int s = EnterFunction(f); edict_t ed; while (true) { s++; // next statement eval_t *a = (eval_t *)Get(_Statements[s].a); eval_t *b = (eval_t *)Get(_Statements[s].b); eval_t *c = (eval_t *)Get(_Statements[s].c); if (--runaway == 0) { RunError("runaway loop error"); } xFunction.profile++; _xStatement = s; if (Trace) { PrintStatement(ref _Statements[s]); } switch ((OP)_Statements[s].op) { case OP.OP_ADD_F: c->_float = a->_float + b->_float; break; case OP.OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP.OP_SUB_F: c->_float = a->_float - b->_float; break; case OP.OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP.OP_MUL_F: c->_float = a->_float * b->_float; break; case OP.OP_MUL_V: c->_float = a->vector[0] * b->vector[0] + a->vector[1] * b->vector[1] + a->vector[2] * b->vector[2]; break; case OP.OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP.OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP.OP_DIV_F: c->_float = a->_float / b->_float; break; case OP.OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP.OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP.OP_GE: c->_float = (a->_float >= b->_float) ? 1 : 0; break; case OP.OP_LE: c->_float = (a->_float <= b->_float) ? 1 : 0; break; case OP.OP_GT: c->_float = (a->_float > b->_float) ? 1 : 0; break; case OP.OP_LT: c->_float = (a->_float < b->_float) ? 1 : 0; break; case OP.OP_AND: c->_float = (a->_float != 0 && b->_float != 0) ? 1 : 0; break; case OP.OP_OR: c->_float = (a->_float != 0 || b->_float != 0) ? 1 : 0; break; case OP.OP_NOT_F: c->_float = (a->_float != 0) ? 0 : 1; break; case OP.OP_NOT_V: c->_float = (a->vector[0] == 0 && a->vector[1] == 0 && a->vector[2] == 0) ? 1 : 0; break; case OP.OP_NOT_S: c->_float = (a->_string == 0 || String.IsNullOrEmpty(GetString(a->_string))) ? 1 : 0; break; case OP.OP_NOT_FNC: c->_float = (a->function == 0) ? 1 : 0; break; case OP.OP_NOT_ENT: c->_float = (Server.ProgToEdict(a->edict) == Server.sv.edicts[0]) ? 1 : 0; break; case OP.OP_EQ_F: c->_float = (a->_float == b->_float) ? 1 : 0; break; case OP.OP_EQ_V: c->_float = ((a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2])) ? 1 : 0; break; case OP.OP_EQ_S: c->_float = (GetString(a->_string) == GetString(b->_string)) ? 1 : 0; //!strcmp(pr_strings + a->_string, pr_strings + b->_string); break; case OP.OP_EQ_E: c->_float = (a->_int == b->_int) ? 1 : 0; break; case OP.OP_EQ_FNC: c->_float = (a->function == b->function) ? 1 : 0; break; case OP.OP_NE_F: c->_float = (a->_float != b->_float) ? 1 : 0; break; case OP.OP_NE_V: c->_float = ((a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2])) ? 1 : 0; break; case OP.OP_NE_S: c->_float = (GetString(a->_string) != GetString(b->_string)) ? 1 : 0; //strcmp(pr_strings + a->_string, pr_strings + b->_string); break; case OP.OP_NE_E: c->_float = (a->_int != b->_int) ? 1 : 0; break; case OP.OP_NE_FNC: c->_float = (a->function != b->function) ? 1 : 0; break; case OP.OP_STORE_F: case OP.OP_STORE_ENT: case OP.OP_STORE_FLD: // integers case OP.OP_STORE_S: case OP.OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP.OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP.OP_STOREP_F: case OP.OP_STOREP_ENT: case OP.OP_STOREP_FLD: // integers case OP.OP_STOREP_S: case OP.OP_STOREP_FNC: // pointers ed = EdictFromAddr(b->_int, out ofs); ed.StoreInt(ofs, a); break; case OP.OP_STOREP_V: ed = EdictFromAddr(b->_int, out ofs); ed.StoreVector(ofs, a); break; case OP.OP_ADDRESS: ed = Server.ProgToEdict(a->edict); if (ed == Server.sv.edicts[0] && Server.IsActive) { RunError("assignment to world entity"); } c->_int = MakeAddr(a->edict, b->_int); break; case OP.OP_LOAD_F: case OP.OP_LOAD_FLD: case OP.OP_LOAD_ENT: case OP.OP_LOAD_S: case OP.OP_LOAD_FNC: ed = Server.ProgToEdict(a->edict); ed.LoadInt(b->_int, c); break; case OP.OP_LOAD_V: ed = Server.ProgToEdict(a->edict); ed.LoadVector(b->_int, c); break; case OP.OP_IFNOT: if (a->_int == 0) { s += _Statements[s].b - 1; // offset the s++ } break; case OP.OP_IF: if (a->_int != 0) { s += _Statements[s].b - 1; // offset the s++ } break; case OP.OP_GOTO: s += _Statements[s].a - 1; // offset the s++ break; case OP.OP_CALL0: case OP.OP_CALL1: case OP.OP_CALL2: case OP.OP_CALL3: case OP.OP_CALL4: case OP.OP_CALL5: case OP.OP_CALL6: case OP.OP_CALL7: case OP.OP_CALL8: _Argc = _Statements[s].op - (int)OP.OP_CALL0; if (a->function == 0) { RunError("NULL function"); } dfunction_t newf = _Functions[a->function]; if (newf.first_statement < 0) { // negative statements are built in functions int i = -newf.first_statement; if (i >= QBuiltins.Count) { RunError("Bad builtin call number"); } QBuiltins.Execute(i); break; } s = EnterFunction(newf); break; case OP.OP_DONE: case OP.OP_RETURN: float *ptr = (float *)_GlobalStructAddr; int sta = _Statements[s].a; ptr[OFS.OFS_RETURN + 0] = *(float *)Get(sta); ptr[OFS.OFS_RETURN + 1] = *(float *)Get(sta + 1); ptr[OFS.OFS_RETURN + 2] = *(float *)Get(sta + 2); s = LeaveFunction(); if (_Depth == exitdepth) { return; // all done } break; case OP.OP_STATE: ed = Server.ProgToEdict(Progs.GlobalStruct.self); #if FPS_20 ed->v.nextthink = pr_global_struct->time + 0.05; #else ed.v.nextthink = Progs.GlobalStruct.time + 0.1f; #endif if (a->_float != ed.v.frame) { ed.v.frame = a->_float; } ed.v.think = b->function; break; default: RunError("Bad opcode %i", _Statements[s].op); break; } } }