using System;
using System.Text;
using OpenTK;

namespace SharpQuake
{
	internal static class QBuiltins
	{
		public static int Count
		{
			get
			{
				return QBuiltins._Builtin.Length;
			}
		}

		private static MsgWriter WriteDest
		{
			get
			{
				switch ((int)QBuiltins.GetFloat(4))
				{
				case 0:
					return server.sv.datagram;
				case 1:
				{
					int num = server.NumForEdict(server.ProgToEdict(progs.GlobalStruct.msg_entity));
					if (num < 1 || num > server.svs.maxclients)
					{
						progs.RunError("WriteDest: not a client", Array.Empty<object>());
					}
					return server.svs.clients[num - 1].message;
				}
				case 2:
					return server.sv.reliable_datagram;
				case 3:
					return server.sv.signon;
				default:
					progs.RunError("WriteDest: bad destination", Array.Empty<object>());
					return null;
				}
			}
		}

		public static void Execute(int num)
		{
			QBuiltins._Builtin[num]();
		}

		public static void ClearState()
		{
			QBuiltins._TempString = -1;
		}

		public static void ReturnEdict(edict_t e)
		{
			QBuiltins.ReturnInt(server.EdictToProg(e));
		}

		public unsafe static void ReturnInt(int value)
		{
			int* ptr = progs.GlobalStructAddr;
			ptr[1] = value;
		}

		public unsafe static void ReturnFloat(float value)
		{
			float* ptr = progs.GlobalStructAddr;
			ptr[1] = value;
		}

		public unsafe static void ReturnVector(ref v3f value)
		{
			float* ptr = progs.GlobalStructAddr;
			ptr[1] = value.x;
			ptr[2] = value.y;
			ptr[3] = value.z;
		}

		public unsafe static void ReturnVector(ref Vector3 value)
		{
			float* ptr = progs.GlobalStructAddr;
			ptr[1] = value.X;
			ptr[2] = value.Y;
			ptr[3] = value.Z;
		}

		public unsafe static string GetString(int parm)
		{
			int* ptr = progs.GlobalStructAddr;
			return progs.GetString(ptr[parm]);
		}

		public unsafe static int GetInt(int parm)
		{
			int* ptr = progs.GlobalStructAddr;
			return ptr[parm];
		}

		public unsafe static float GetFloat(int parm)
		{
			float* ptr = progs.GlobalStructAddr;
			return ptr[parm];
		}

		public unsafe static float* GetVector(int parm)
		{
			float* ptr = progs.GlobalStructAddr;
			return ptr + parm;
		}

		public unsafe static edict_t GetEdict(int parm)
		{
			int* ptr = progs.GlobalStructAddr;
			return server.ProgToEdict(ptr[parm]);
		}

		public static void PF_changeyaw()
		{
			edict_t edict_t = server.ProgToEdict(progs.GlobalStruct.self);
			float num = mathlib.AngleMod((double)edict_t.v.angles.y);
			float ideal_yaw = edict_t.v.ideal_yaw;
			float yaw_speed = edict_t.v.yaw_speed;
			if (num == ideal_yaw)
			{
				return;
			}
			float num2 = ideal_yaw - num;
			if (ideal_yaw > num)
			{
				if (num2 >= 180f)
				{
					num2 -= 360f;
				}
			}
			else if (num2 <= -180f)
			{
				num2 += 360f;
			}
			if (num2 > 0f)
			{
				if (num2 > yaw_speed)
				{
					num2 = yaw_speed;
				}
			}
			else if (num2 < -yaw_speed)
			{
				num2 = -yaw_speed;
			}
			edict_t.v.angles.y = mathlib.AngleMod((double)(num + num2));
		}

		private static int SetTempString(string value)
		{
			if (QBuiltins._TempString == -1)
			{
				QBuiltins._TempString = progs.NewString(value);
			}
			else
			{
				progs.SetString(QBuiltins._TempString, value);
			}
			return QBuiltins._TempString;
		}

		private static string PF_VarString(int first)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			for (int i = first; i < progs.Argc; i++)
			{
				stringBuilder.Append(QBuiltins.GetString(4 + i * 3));
			}
			return stringBuilder.ToString();
		}

		private unsafe static void Copy(float* src, ref v3f dest)
		{
			dest.x = *src;
			dest.y = src[1];
			dest.z = src[2];
		}

		private unsafe static void Copy(float* src, out Vector3 dest)
		{
			dest.X = *src;
			dest.Y = src[1];
			dest.Z = src[2];
		}

		private static void PF_error()
		{
			string text = QBuiltins.PF_VarString(0);
			Con.Print("======SERVER ERROR in {0}:\n{1}\n", new object[]
			{
				progs.GetString(progs.xFunction.s_name),
				text
			});
			progs.Print(server.ProgToEdict(progs.GlobalStruct.self));
			host.Error("Program error", Array.Empty<object>());
		}

		private static void PF_objerror()
		{
			string text = QBuiltins.PF_VarString(0);
			Con.Print("======OBJECT ERROR in {0}:\n{1}\n", new object[]
			{
				QBuiltins.GetString(progs.xFunction.s_name),
				text
			});
			edict_t ed = server.ProgToEdict(progs.GlobalStruct.self);
			progs.Print(ed);
			server.FreeEdict(ed);
			host.Error("Program error", Array.Empty<object>());
		}

		private unsafe static void PF_makevectors()
		{
			float* vector = QBuiltins.GetVector(4);
			Vector3 vector2 = new Vector3(*vector, vector[1], vector[2]);
			Vector3 vector3;
			Vector3 vector4;
			Vector3 vector5;
			mathlib.AngleVectors(ref vector2, out vector3, out vector4, out vector5);
			mathlib.Copy(ref vector3, out progs.GlobalStruct.v_forward);
			mathlib.Copy(ref vector4, out progs.GlobalStruct.v_right);
			mathlib.Copy(ref vector5, out progs.GlobalStruct.v_up);
		}

		private static void PF_setorigin()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			QBuiltins.Copy(QBuiltins.GetVector(7), ref edict.v.origin);
			server.LinkEdict(edict, false);
		}

		private static void SetMinMaxSize(edict_t e, ref Vector3 min, ref Vector3 max, bool rotate)
		{
			if (min.X > max.X || min.Y > max.Y || min.Z > max.Z)
			{
				progs.RunError("backwards mins/maxs", Array.Empty<object>());
			}
			Vector3 vector = min;
			Vector3 vector2 = max;
			mathlib.Copy(ref vector, out e.v.mins);
			mathlib.Copy(ref vector2, out e.v.maxs);
			Vector3 vector3 = max - min;
			mathlib.Copy(ref vector3, out e.v.size);
			server.LinkEdict(e, false);
		}

		private unsafe static void PF_setsize()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			float* vector = QBuiltins.GetVector(7);
			float* vector2 = QBuiltins.GetVector(10);
			Vector3 vector3;
			QBuiltins.Copy(vector, out vector3);
			Vector3 vector4;
			QBuiltins.Copy(vector2, out vector4);
			QBuiltins.SetMinMaxSize(edict, ref vector3, ref vector4, false);
		}

		private static void PF_setmodel()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			int @int = QBuiltins.GetInt(7);
			string @string = progs.GetString(@int);
			int i = 0;
			while (i < server.sv.model_precache.Length)
			{
				string text = server.sv.model_precache[i];
				if (text == null)
				{
					break;
				}
				if (text == @string)
				{
					edict.v.model = @int;
					edict.v.modelindex = (float)i;
					model_t model_t = server.sv.models[(int)edict.v.modelindex];
					if (model_t != null)
					{
						QBuiltins.SetMinMaxSize(edict, ref model_t.mins, ref model_t.maxs, true);
						return;
					}
					QBuiltins.SetMinMaxSize(edict, ref common.ZeroVector, ref common.ZeroVector, true);
					return;
				}
				else
				{
					i++;
				}
			}
			progs.RunError("no precache: {0}\n", new object[]
			{
				@string
			});
		}

		private static void PF_bprint()
		{
			server.BroadcastPrint(QBuiltins.PF_VarString(0), Array.Empty<object>());
		}

		private static void PF_sprint()
		{
			int num = server.NumForEdict(QBuiltins.GetEdict(4));
			string s = QBuiltins.PF_VarString(1);
			if (num < 1 || num > server.svs.maxclients)
			{
				Con.Print("tried to sprint to a non-client\n", Array.Empty<object>());
				return;
			}
			client_t client_t = server.svs.clients[num - 1];
			client_t.message.WriteChar(8);
			client_t.message.WriteString(s);
		}

		private static void PF_centerprint()
		{
			int num = server.NumForEdict(QBuiltins.GetEdict(4));
			string s = QBuiltins.PF_VarString(1);
			if (num < 1 || num > server.svs.maxclients)
			{
				Con.Print("tried to centerprint to a non-client\n", Array.Empty<object>());
				return;
			}
			client_t client_t = server.svs.clients[num - 1];
			client_t.message.WriteChar(26);
			client_t.message.WriteString(s);
		}

		private static void PF_normalize()
		{
			Vector3 vector;
			QBuiltins.Copy(QBuiltins.GetVector(4), out vector);
			mathlib.Normalize(ref vector);
			QBuiltins.ReturnVector(ref vector);
		}

		private unsafe static void PF_vlen()
		{
			float* vector = QBuiltins.GetVector(4);
			QBuiltins.ReturnFloat((float)Math.Sqrt((double)(*vector * *vector + vector[1] * vector[1] + vector[2] * vector[2])));
		}

		private unsafe static void PF_vectoyaw()
		{
			float* vector = QBuiltins.GetVector(4);
			float num;
			if (vector[1] == 0f && *vector == 0f)
			{
				num = 0f;
			}
			else
			{
				num = (float)((int)(Math.Atan2((double)vector[1], (double)(*vector)) * 180.0 / 3.1415926535897931));
				if (num < 0f)
				{
					num += 360f;
				}
			}
			QBuiltins.ReturnFloat(num);
		}

		private unsafe static void PF_vectoangles()
		{
			float* vector = QBuiltins.GetVector(4);
			float num;
			float num2;
			if (vector[1] == 0f && *vector == 0f)
			{
				num = 0f;
				if (vector[2] > 0f)
				{
					num2 = 90f;
				}
				else
				{
					num2 = 270f;
				}
			}
			else
			{
				num = (float)((int)(Math.Atan2((double)vector[1], (double)(*vector)) * 180.0 / 3.1415926535897931));
				if (num < 0f)
				{
					num += 360f;
				}
				float num3 = (float)Math.Sqrt((double)(*vector * *vector + vector[1] * vector[1]));
				num2 = (float)((int)(Math.Atan2((double)vector[2], (double)num3) * 180.0 / 3.1415926535897931));
				if (num2 < 0f)
				{
					num2 += 360f;
				}
			}
			Vector3 vector2 = new Vector3(num2, num, 0f);
			QBuiltins.ReturnVector(ref vector2);
		}

		private static void PF_random()
		{
			QBuiltins.ReturnFloat((float)(sys.Random() & 32767) / 32767f);
		}

		private unsafe static void PF_particle()
		{
			float* vector = QBuiltins.GetVector(4);
			float* vector2 = QBuiltins.GetVector(7);
			float @float = QBuiltins.GetFloat(10);
			float float2 = QBuiltins.GetFloat(13);
			Vector3 vector3;
			QBuiltins.Copy(vector, out vector3);
			Vector3 vector4;
			QBuiltins.Copy(vector2, out vector4);
			server.StartParticle(ref vector3, ref vector4, (int)@float, (int)float2);
		}

		private unsafe static void PF_ambientsound()
		{
			float* vector = QBuiltins.GetVector(4);
			string @string = QBuiltins.GetString(7);
			float @float = QBuiltins.GetFloat(10);
			float float2 = QBuiltins.GetFloat(13);
			int num = 0;
			while (num < server.sv.sound_precache.Length && server.sv.sound_precache[num] != null)
			{
				if (@string == server.sv.sound_precache[num])
				{
					MsgWriter signon = server.sv.signon;
					signon.WriteByte(29);
					for (int i = 0; i < 3; i++)
					{
						signon.WriteCoord(vector[i]);
					}
					signon.WriteByte(num);
					signon.WriteByte((int)(@float * 255f));
					signon.WriteByte((int)(float2 * 64f));
					return;
				}
				num++;
			}
			Con.Print("no precache: {0}\n", new object[]
			{
				@string
			});
		}

		private static void PF_sound()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			int channel = (int)QBuiltins.GetFloat(7);
			string @string = QBuiltins.GetString(10);
			int volume = (int)(QBuiltins.GetFloat(13) * 255f);
			float @float = QBuiltins.GetFloat(16);
			server.StartSound(edict, channel, @string, volume, @float);
		}

		private static void PF_break()
		{
			Con.Print("break statement\n", Array.Empty<object>());
		}

		private unsafe static void PF_traceline()
		{
			float* vector = QBuiltins.GetVector(4);
			float* vector2 = QBuiltins.GetVector(7);
			int type = (int)QBuiltins.GetFloat(10);
			edict_t edict = QBuiltins.GetEdict(13);
			Vector3 vector3;
			QBuiltins.Copy(vector, out vector3);
			Vector3 vector4;
			QBuiltins.Copy(vector2, out vector4);
			trace_t trace_t = server.Move(ref vector3, ref common.ZeroVector, ref common.ZeroVector, ref vector4, type, edict);
			progs.GlobalStruct.trace_allsolid = (float)(trace_t.allsolid ? 1 : 0);
			progs.GlobalStruct.trace_startsolid = (float)(trace_t.startsolid ? 1 : 0);
			progs.GlobalStruct.trace_fraction = trace_t.fraction;
			progs.GlobalStruct.trace_inwater = (float)(trace_t.inwater ? 1 : 0);
			progs.GlobalStruct.trace_inopen = (float)(trace_t.inopen ? 1 : 0);
			mathlib.Copy(ref trace_t.endpos, out progs.GlobalStruct.trace_endpos);
			mathlib.Copy(ref trace_t.plane.normal, out progs.GlobalStruct.trace_plane_normal);
			progs.GlobalStruct.trace_plane_dist = trace_t.plane.dist;
			if (trace_t.ent != null)
			{
				progs.GlobalStruct.trace_ent = server.EdictToProg(trace_t.ent);
				return;
			}
			progs.GlobalStruct.trace_ent = server.EdictToProg(server.sv.edicts[0]);
		}

		private static void PF_checkpos()
		{
		}

		private static int PF_newcheckclient(int check)
		{
			if (check < 1)
			{
				check = 1;
			}
			if (check > server.svs.maxclients)
			{
				check = server.svs.maxclients;
			}
			int num = check + 1;
			if (check == server.svs.maxclients)
			{
				num = 1;
			}
			edict_t edict_t;
			for (;;)
			{
				if (num == server.svs.maxclients + 1)
				{
					num = 1;
				}
				edict_t = server.EdictNum(num);
				if (num == check || (!edict_t.free && edict_t.v.health > 0f && ((int)edict_t.v.flags & 128) == 0))
				{
					break;
				}
				num++;
			}
			Vector3 vector = common.ToVector(ref edict_t.v.origin) + common.ToVector(ref edict_t.v.view_ofs);
			byte[] array = Mod.LeafPVS(Mod.PointInLeaf(ref vector, server.sv.worldmodel), server.sv.worldmodel);
			Buffer.BlockCopy(array, 0, QBuiltins._CheckPvs, 0, array.Length);
			return num;
		}

		private static void PF_checkclient()
		{
			if (server.sv.time - server.sv.lastchecktime >= 0.1)
			{
				server.sv.lastcheck = QBuiltins.PF_newcheckclient(server.sv.lastcheck);
				server.sv.lastchecktime = server.sv.time;
			}
			edict_t edict_t = server.EdictNum(server.sv.lastcheck);
			if (edict_t.free || edict_t.v.health <= 0f)
			{
				QBuiltins.ReturnEdict(server.sv.edicts[0]);
				return;
			}
			edict_t edict_t2 = server.ProgToEdict(progs.GlobalStruct.self);
			Vector3 vector = common.ToVector(ref edict_t2.v.origin) + common.ToVector(ref edict_t2.v.view_ofs);
			mleaf_t value = Mod.PointInLeaf(ref vector, server.sv.worldmodel);
			int num = Array.IndexOf<mleaf_t>(server.sv.worldmodel.leafs, value) - 1;
			if (num < 0 || ((int)QBuiltins._CheckPvs[num >> 3] & 1 << (num & 7)) == 0)
			{
				QBuiltins._NotVisCount++;
				QBuiltins.ReturnEdict(server.sv.edicts[0]);
				return;
			}
			QBuiltins._InVisCount++;
			QBuiltins.ReturnEdict(edict_t);
		}

		private static void PF_stuffcmd()
		{
			int num = server.NumForEdict(QBuiltins.GetEdict(4));
			if (num < 1 || num > server.svs.maxclients)
			{
				progs.RunError("Parm 0 not a client", Array.Empty<object>());
			}
			string @string = QBuiltins.GetString(7);
			client_t hostClient = host.HostClient;
			host.HostClient = server.svs.clients[num - 1];
			host.ClientCommands("{0}", new object[]
			{
				@string
			});
			host.HostClient = hostClient;
		}

		private static void PF_localcmd()
		{
			Cbuf.AddText(QBuiltins.GetString(4));
		}

		private static void PF_cvar()
		{
			QBuiltins.ReturnFloat(cvar.GetValue(QBuiltins.GetString(4)));
		}

		private static void PF_cvar_set()
		{
			cvar.Set(QBuiltins.GetString(4), QBuiltins.GetString(7));
		}

		private unsafe static void PF_findradius()
		{
			edict_t e = server.sv.edicts[0];
			float* vector = QBuiltins.GetVector(4);
			float @float = QBuiltins.GetFloat(7);
			Vector3 left;
			QBuiltins.Copy(vector, out left);
			for (int i = 1; i < server.sv.num_edicts; i++)
			{
				edict_t edict_t = server.sv.edicts[i];
				if (!edict_t.free && edict_t.v.solid != 0f && (left - (common.ToVector(ref edict_t.v.origin) + (common.ToVector(ref edict_t.v.mins) + common.ToVector(ref edict_t.v.maxs)) * 0.5f)).Length <= @float)
				{
					edict_t.v.chain = server.EdictToProg(e);
					e = edict_t;
				}
			}
			QBuiltins.ReturnEdict(e);
		}

		private static void PF_dprint()
		{
			Con.DPrint(QBuiltins.PF_VarString(0), Array.Empty<object>());
		}

		private static void PF_ftos()
		{
			float @float = QBuiltins.GetFloat(4);
			if (@float == (float)((int)@float))
			{
				QBuiltins.SetTempString(string.Format("{0}", (int)@float));
			}
			else
			{
				QBuiltins.SetTempString(string.Format("{0:F1}", @float));
			}
			QBuiltins.ReturnInt(QBuiltins._TempString);
		}

		private static void PF_fabs()
		{
			QBuiltins.ReturnFloat(Math.Abs(QBuiltins.GetFloat(4)));
		}

		private unsafe static void PF_vtos()
		{
			float* vector = QBuiltins.GetVector(4);
			QBuiltins.SetTempString(string.Format("'{0,5:F1} {1,5:F1} {2,5:F1}'", *vector, vector[1], vector[2]));
			QBuiltins.ReturnInt(QBuiltins._TempString);
		}

		private static void PF_Spawn()
		{
			QBuiltins.ReturnEdict(server.AllocEdict());
		}

		private static void PF_Remove()
		{
			server.FreeEdict(QBuiltins.GetEdict(4));
		}

		private static void PF_Find()
		{
			int i = QBuiltins.GetInt(4);
			int @int = QBuiltins.GetInt(7);
			string @string = QBuiltins.GetString(10);
			if (@string == null)
			{
				progs.RunError("PF_Find: bad search string", Array.Empty<object>());
			}
			for (i++; i < server.sv.num_edicts; i++)
			{
				edict_t edict_t = server.EdictNum(i);
				if (!edict_t.free)
				{
					string string2 = progs.GetString(edict_t.GetInt(@int));
					if (!string.IsNullOrEmpty(string2) && string2 == @string)
					{
						QBuiltins.ReturnEdict(edict_t);
						return;
					}
				}
			}
			QBuiltins.ReturnEdict(server.sv.edicts[0]);
		}

		private static void CheckEmptyString(string s)
		{
			if (s == null || s.Length == 0 || s[0] <= ' ')
			{
				progs.RunError("Bad string", Array.Empty<object>());
			}
		}

		private static void PF_precache_file()
		{
			QBuiltins.ReturnInt(QBuiltins.GetInt(4));
		}

		private static void PF_precache_sound()
		{
			if (!server.IsLoading)
			{
				progs.RunError("PF_Precache_*: Precache can only be done in spawn functions", Array.Empty<object>());
			}
			string @string = QBuiltins.GetString(4);
			QBuiltins.ReturnInt(QBuiltins.GetInt(4));
			QBuiltins.CheckEmptyString(@string);
			for (int i = 0; i < 256; i++)
			{
				if (server.sv.sound_precache[i] == null)
				{
					server.sv.sound_precache[i] = @string;
					return;
				}
				if (server.sv.sound_precache[i] == @string)
				{
					return;
				}
			}
			progs.RunError("PF_precache_sound: overflow", Array.Empty<object>());
		}

		private static void PF_precache_model()
		{
			if (!server.IsLoading)
			{
				progs.RunError("PF_Precache_*: Precache can only be done in spawn functions", Array.Empty<object>());
			}
			string @string = QBuiltins.GetString(4);
			QBuiltins.ReturnInt(QBuiltins.GetInt(4));
			QBuiltins.CheckEmptyString(@string);
			for (int i = 0; i < 256; i++)
			{
				if (server.sv.model_precache[i] == null)
				{
					server.sv.model_precache[i] = @string;
					server.sv.models[i] = Mod.ForName(@string, true);
					return;
				}
				if (server.sv.model_precache[i] == @string)
				{
					return;
				}
			}
			progs.RunError("PF_precache_model: overflow", Array.Empty<object>());
		}

		private static void PF_coredump()
		{
			progs.PrintEdicts();
		}

		private static void PF_traceon()
		{
			progs.Trace = true;
		}

		private static void PF_traceoff()
		{
			progs.Trace = false;
		}

		private static void PF_eprint()
		{
			progs.PrintNum(server.NumForEdict(QBuiltins.GetEdict(4)));
		}

		private static void PF_walkmove()
		{
			edict_t edict_t = server.ProgToEdict(progs.GlobalStruct.self);
			float num = QBuiltins.GetFloat(4);
			float @float = QBuiltins.GetFloat(7);
			if (((int)edict_t.v.flags & 515) == 0)
			{
				QBuiltins.ReturnFloat(0f);
				return;
			}
			num = (float)((double)num * 3.1415926535897931 * 2.0 / 360.0);
			v3f v3f;
			v3f.x = (float)Math.Cos((double)num) * @float;
			v3f.y = (float)Math.Sin((double)num) * @float;
			v3f.z = 0f;
			dfunction_t xFunction = progs.xFunction;
			int self = progs.GlobalStruct.self;
			QBuiltins.ReturnFloat((float)(server.MoveStep(edict_t, ref v3f, true) ? 1 : 0));
			progs.xFunction = xFunction;
			progs.GlobalStruct.self = self;
		}

		private static void PF_droptofloor()
		{
			edict_t edict_t = server.ProgToEdict(progs.GlobalStruct.self);
			Vector3 vector;
			mathlib.Copy(ref edict_t.v.origin, out vector);
			Vector3 vector2;
			mathlib.Copy(ref edict_t.v.mins, out vector2);
			Vector3 vector3;
			mathlib.Copy(ref edict_t.v.maxs, out vector3);
			Vector3 vector4 = vector;
			vector4.Z -= 256f;
			trace_t trace_t = server.Move(ref vector, ref vector2, ref vector3, ref vector4, 0, edict_t);
			if (trace_t.fraction == 1f || trace_t.allsolid)
			{
				QBuiltins.ReturnFloat(0f);
				return;
			}
			mathlib.Copy(ref trace_t.endpos, out edict_t.v.origin);
			server.LinkEdict(edict_t, false);
			edict_t.v.flags = (float)((int)edict_t.v.flags | 512);
			edict_t.v.groundentity = server.EdictToProg(trace_t.ent);
			QBuiltins.ReturnFloat(1f);
		}

		private static void PF_lightstyle()
		{
			int num = (int)QBuiltins.GetFloat(4);
			string @string = QBuiltins.GetString(7);
			server.sv.lightstyles[num] = @string;
			if (!server.IsActive)
			{
				return;
			}
			for (int i = 0; i < server.svs.maxclients; i++)
			{
				client_t client_t = server.svs.clients[i];
				if (client_t.active || client_t.spawned)
				{
					client_t.message.WriteChar(12);
					client_t.message.WriteChar(num);
					client_t.message.WriteString(@string);
				}
			}
		}

		private static void PF_rint()
		{
			float @float = QBuiltins.GetFloat(4);
			if (@float > 0f)
			{
				QBuiltins.ReturnFloat((float)((int)((double)@float + 0.5)));
				return;
			}
			QBuiltins.ReturnFloat((float)((int)((double)@float - 0.5)));
		}

		private static void PF_floor()
		{
			QBuiltins.ReturnFloat((float)Math.Floor((double)QBuiltins.GetFloat(4)));
		}

		private static void PF_ceil()
		{
			QBuiltins.ReturnFloat((float)Math.Ceiling((double)QBuiltins.GetFloat(4)));
		}

		private static void PF_checkbottom()
		{
			QBuiltins.ReturnFloat((float)(server.CheckBottom(QBuiltins.GetEdict(4)) ? 1 : 0));
		}

		private static void PF_pointcontents()
		{
			Vector3 vector;
			QBuiltins.Copy(QBuiltins.GetVector(4), out vector);
			QBuiltins.ReturnFloat((float)server.PointContents(ref vector));
		}

		private static void PF_nextent()
		{
			int num = server.NumForEdict(QBuiltins.GetEdict(4));
			edict_t edict_t;
			for (;;)
			{
				num++;
				if (num == server.sv.num_edicts)
				{
					break;
				}
				edict_t = server.EdictNum(num);
				if (!edict_t.free)
				{
					goto Block_2;
				}
			}
			QBuiltins.ReturnEdict(server.sv.edicts[0]);
			return;
			Block_2:
			QBuiltins.ReturnEdict(edict_t);
		}

		private static void PF_aim()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			QBuiltins.GetFloat(7);
			Vector3 vector = common.ToVector(ref edict.v.origin);
			vector.Z += 20f;
			Vector3 vector2;
			mathlib.Copy(ref progs.GlobalStruct.v_forward, out vector2);
			Vector3 left = vector + vector2 * 2048f;
			trace_t trace_t = server.Move(ref vector, ref common.ZeroVector, ref common.ZeroVector, ref left, 0, edict);
			if (trace_t.ent != null && trace_t.ent.v.takedamage == 2f && (host.TeamPlay == 0f || edict.v.team <= 0f || edict.v.team != trace_t.ent.v.team))
			{
				QBuiltins.ReturnVector(ref progs.GlobalStruct.v_forward);
				return;
			}
			Vector3 vector3 = vector2;
			float num = server.Aim;
			edict_t edict_t = null;
			for (int i = 1; i < server.sv.num_edicts; i++)
			{
				edict_t edict_t2 = server.sv.edicts[i];
				if (edict_t2.v.takedamage == 2f && edict_t2 != edict && (host.TeamPlay == 0f || edict.v.team <= 0f || edict.v.team != edict_t2.v.team))
				{
					v3f v3f;
					mathlib.VectorAdd(ref edict_t2.v.mins, ref edict_t2.v.maxs, out v3f);
					mathlib.VectorMA(ref edict_t2.v.origin, 0.5f, ref v3f, out v3f);
					mathlib.Copy(ref v3f, out left);
					vector2 = left - vector;
					mathlib.Normalize(ref vector2);
					float num2 = Vector3.Dot(vector2, common.ToVector(ref progs.GlobalStruct.v_forward));
					if (num2 >= num)
					{
						trace_t = server.Move(ref vector, ref common.ZeroVector, ref common.ZeroVector, ref left, 0, edict);
						if (trace_t.ent == edict_t2)
						{
							num = num2;
							edict_t = edict_t2;
						}
					}
				}
			}
			if (edict_t != null)
			{
				v3f v3f2;
				mathlib.VectorSubtract(ref edict_t.v.origin, ref edict.v.origin, out v3f2);
				float scale = mathlib.DotProduct(ref v3f2, ref progs.GlobalStruct.v_forward);
				v3f v3f3;
				mathlib.VectorScale(ref progs.GlobalStruct.v_forward, scale, out v3f3);
				v3f3.z = v3f2.z;
				mathlib.Normalize(ref v3f3);
				QBuiltins.ReturnVector(ref v3f3);
				return;
			}
			QBuiltins.ReturnVector(ref vector3);
		}

		private static void PF_WriteByte()
		{
			QBuiltins.WriteDest.WriteByte((int)QBuiltins.GetFloat(7));
		}

		private static void PF_WriteChar()
		{
			QBuiltins.WriteDest.WriteChar((int)QBuiltins.GetFloat(7));
		}

		private static void PF_WriteShort()
		{
			QBuiltins.WriteDest.WriteShort((int)QBuiltins.GetFloat(7));
		}

		private static void PF_WriteLong()
		{
			QBuiltins.WriteDest.WriteLong((int)QBuiltins.GetFloat(7));
		}

		private static void PF_WriteAngle()
		{
			QBuiltins.WriteDest.WriteAngle(QBuiltins.GetFloat(7));
		}

		private static void PF_WriteCoord()
		{
			QBuiltins.WriteDest.WriteCoord(QBuiltins.GetFloat(7));
		}

		private static void PF_WriteString()
		{
			QBuiltins.WriteDest.WriteString(QBuiltins.GetString(7));
		}

		private static void PF_WriteEntity()
		{
			QBuiltins.WriteDest.WriteShort(server.NumForEdict(QBuiltins.GetEdict(7)));
		}

		private static void PF_makestatic()
		{
			edict_t edict = QBuiltins.GetEdict(4);
			MsgWriter signon = server.sv.signon;
			signon.WriteByte(20);
			signon.WriteByte(server.ModelIndex(progs.GetString(edict.v.model)));
			signon.WriteByte((int)edict.v.frame);
			signon.WriteByte((int)edict.v.colormap);
			signon.WriteByte((int)edict.v.skin);
			for (int i = 0; i < 3; i++)
			{
				signon.WriteCoord(mathlib.Comp(ref edict.v.origin, i));
				signon.WriteAngle(mathlib.Comp(ref edict.v.angles, i));
			}
			server.FreeEdict(edict);
		}

		private static void PF_setspawnparms()
		{
			int num = server.NumForEdict(QBuiltins.GetEdict(4));
			if (num < 1 || num > server.svs.maxclients)
			{
				progs.RunError("Entity is not a client", Array.Empty<object>());
			}
			client_t client_t = server.svs.clients[num - 1];
			progs.GlobalStruct.SetParams(client_t.spawn_parms);
		}

		private static void PF_changelevel()
		{
			if (server.svs.changelevel_issued)
			{
				return;
			}
			server.svs.changelevel_issued = true;
			string @string = QBuiltins.GetString(4);
			Cbuf.AddText(string.Format("changelevel {0}\n", @string));
		}

		private static void PF_Fixme()
		{
			progs.RunError("unimplemented bulitin", Array.Empty<object>());
		}

		private const int MAX_CHECK = 16;

		private const int MSG_BROADCAST = 0;

		private const int MSG_ONE = 1;

		private const int MSG_ALL = 2;

		private const int MSG_INIT = 3;

		private static builtin_t[] _Builtin = new builtin_t[]
		{
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_makevectors),
			new builtin_t(QBuiltins.PF_setorigin),
			new builtin_t(QBuiltins.PF_setmodel),
			new builtin_t(QBuiltins.PF_setsize),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_break),
			new builtin_t(QBuiltins.PF_random),
			new builtin_t(QBuiltins.PF_sound),
			new builtin_t(QBuiltins.PF_normalize),
			new builtin_t(QBuiltins.PF_error),
			new builtin_t(QBuiltins.PF_objerror),
			new builtin_t(QBuiltins.PF_vlen),
			new builtin_t(QBuiltins.PF_vectoyaw),
			new builtin_t(QBuiltins.PF_Spawn),
			new builtin_t(QBuiltins.PF_Remove),
			new builtin_t(QBuiltins.PF_traceline),
			new builtin_t(QBuiltins.PF_checkclient),
			new builtin_t(QBuiltins.PF_Find),
			new builtin_t(QBuiltins.PF_precache_sound),
			new builtin_t(QBuiltins.PF_precache_model),
			new builtin_t(QBuiltins.PF_stuffcmd),
			new builtin_t(QBuiltins.PF_findradius),
			new builtin_t(QBuiltins.PF_bprint),
			new builtin_t(QBuiltins.PF_sprint),
			new builtin_t(QBuiltins.PF_dprint),
			new builtin_t(QBuiltins.PF_ftos),
			new builtin_t(QBuiltins.PF_vtos),
			new builtin_t(QBuiltins.PF_coredump),
			new builtin_t(QBuiltins.PF_traceon),
			new builtin_t(QBuiltins.PF_traceoff),
			new builtin_t(QBuiltins.PF_eprint),
			new builtin_t(QBuiltins.PF_walkmove),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_droptofloor),
			new builtin_t(QBuiltins.PF_lightstyle),
			new builtin_t(QBuiltins.PF_rint),
			new builtin_t(QBuiltins.PF_floor),
			new builtin_t(QBuiltins.PF_ceil),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_checkbottom),
			new builtin_t(QBuiltins.PF_pointcontents),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_fabs),
			new builtin_t(QBuiltins.PF_aim),
			new builtin_t(QBuiltins.PF_cvar),
			new builtin_t(QBuiltins.PF_localcmd),
			new builtin_t(QBuiltins.PF_nextent),
			new builtin_t(QBuiltins.PF_particle),
			new builtin_t(QBuiltins.PF_changeyaw),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_vectoangles),
			new builtin_t(QBuiltins.PF_WriteByte),
			new builtin_t(QBuiltins.PF_WriteChar),
			new builtin_t(QBuiltins.PF_WriteShort),
			new builtin_t(QBuiltins.PF_WriteLong),
			new builtin_t(QBuiltins.PF_WriteCoord),
			new builtin_t(QBuiltins.PF_WriteAngle),
			new builtin_t(QBuiltins.PF_WriteString),
			new builtin_t(QBuiltins.PF_WriteEntity),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(server.MoveToGoal),
			new builtin_t(QBuiltins.PF_precache_file),
			new builtin_t(QBuiltins.PF_makestatic),
			new builtin_t(QBuiltins.PF_changelevel),
			new builtin_t(QBuiltins.PF_Fixme),
			new builtin_t(QBuiltins.PF_cvar_set),
			new builtin_t(QBuiltins.PF_centerprint),
			new builtin_t(QBuiltins.PF_ambientsound),
			new builtin_t(QBuiltins.PF_precache_model),
			new builtin_t(QBuiltins.PF_precache_sound),
			new builtin_t(QBuiltins.PF_precache_file),
			new builtin_t(QBuiltins.PF_setspawnparms)
		};

		private static byte[] _CheckPvs = new byte[1024];

		private static int _TempString = -1;

		private static int _InVisCount;

		private static int _NotVisCount;
	}
}
