/// <summary> /// PF_checkclient /// Returns a client (or object that has a client enemy) that would be a /// valid target. /// /// If there are more than one valid options, they are cycled each frame /// /// If (self.origin + self.viewofs) is not in the PVS of the current target, /// it is not returned at all. /// /// name checkclient () /// </summary> static void PF_checkclient() { // find a new check if on a new frame if (Server.sv.time - Server.sv.lastchecktime >= 0.1) { Server.sv.lastcheck = PF_newcheckclient(Server.sv.lastcheck); Server.sv.lastchecktime = Server.sv.time; } // return check if it might be visible edict_t ent = Server.EdictNum(Server.sv.lastcheck); if (ent.free || ent.v.health <= 0) { ReturnEdict(Server.sv.edicts[0]); return; } // if current entity can't possibly see the check entity, return 0 edict_t self = Server.ProgToEdict(Progs.GlobalStruct.self); Vector3 view = Common.ToVector(ref self.v.origin) + Common.ToVector(ref self.v.view_ofs); mleaf_t leaf = Mod.PointInLeaf(ref view, Server.sv.worldmodel); int l = Array.IndexOf(Server.sv.worldmodel.leafs, leaf) - 1; if ((l < 0) || (_CheckPvs[l >> 3] & (1 << (l & 7))) == 0) { _NotVisCount++; ReturnEdict(Server.sv.edicts[0]); return; } // might be able to see it _InVisCount++; ReturnEdict(ent); }
/// <summary> /// #define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o])) /// </summary> public static unsafe edict_t GetEdict(int parm) { int * ptr = (int *)Progs.GlobalStructAddr; edict_t ed = Server.ProgToEdict(ptr[parm]); return(ed); }
/* * =============== * PF_droptofloor * * void() droptofloor * =============== */ static void PF_droptofloor() { edict_t ent = Server.ProgToEdict(Progs.GlobalStruct.self); Vector3 org, mins, maxs; Mathlib.Copy(ref ent.v.origin, out org); Mathlib.Copy(ref ent.v.mins, out mins); Mathlib.Copy(ref ent.v.maxs, out maxs); Vector3 end = org; end.Z -= 256; trace_t trace = Server.Move(ref org, ref mins, ref maxs, ref end, 0, ent); if (trace.fraction == 1 || trace.allsolid) { ReturnFloat(0); } else { Mathlib.Copy(ref trace.endpos, out ent.v.origin); Server.LinkEdict(ent, false); ent.v.flags = (int)ent.v.flags | EdictFlags.FL_ONGROUND; ent.v.groundentity = Server.EdictToProg(trace.ent); ReturnFloat(1); } }
/// <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; }
public static edict_t EdictFromAddr(int addr, out int ofs) { int prog = (addr >> 16) & 0xFFFF; ofs = addr & 0xFFFF; return(Server.ProgToEdict(prog)); }
/// <summary> /// PF_errror /// This is a TERMINAL error, which will kill off the entire server. /// Dumps self. /// error(value) /// </summary> static void PF_error() { string s = PF_VarString(0); Con.Print("======SERVER ERROR in {0}:\n{1}\n", Progs.GetString(Progs.xFunction.s_name), s); edict_t ed = Server.ProgToEdict(Progs.GlobalStruct.self); Progs.Print(ed); Host.Error("Program error"); }
/// <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); }
/* * ============== * PF_changeyaw * * This was a major timewaster in progs, so it was converted to C * ============== */ public static void PF_changeyaw() { edict_t ent = Server.ProgToEdict(Progs.GlobalStruct.self); float current = Mathlib.AngleMod(ent.v.angles.y); float ideal = ent.v.ideal_yaw; float speed = ent.v.yaw_speed; if (current == ideal) { return; } float move = ideal - current; if (ideal > current) { if (move >= 180) { move = move - 360; } } else { if (move <= -180) { move = move + 360; } } if (move > 0) { if (move > speed) { move = speed; } } else { if (move < -speed) { move = -speed; } } ent.v.angles.y = Mathlib.AngleMod(current + move); }
/// <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; } } }