]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/Main.qc
Instead of wasting actual entities, I now use the TempEntity method
[divverent/nexuiz.git] / data / qcsrc / client / Main.qc
1 // --------------------------------------------------------------------------\r
2 // BEGIN REQUIRED CSQC FUNCTIONS\r
3 //include "main.qh"\r
4 \r
5 void() menu_show_error =\r
6 {\r
7         drawstring('0 200', "ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!", '8 8 0', '1 0 0', 1, 0);\r
8 };\r
9 \r
10 // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load)\r
11 // Useful for precaching things\r
12 \r
13 void() menu_sub_null =\r
14 {\r
15 };\r
16 \r
17 // let's make this a general data buffer...\r
18 float databuf;\r
19 float using_gps;\r
20 \r
21 void CSQC_Init(void)\r
22 {\r
23         float i;\r
24 \r
25         menu_visible = FALSE;\r
26         menu_show = menu_show_error;\r
27         menu_action = menu_sub_null;\r
28         using_gps = false;\r
29         //ctf_temp_1 = "";\r
30         localcmd("alias order \"cmd order $*\"");\r
31         //registercmd("ctf_menu");\r
32         registercmd("ons_map");\r
33         //registercmd("menu_action");\r
34 \r
35         registercvar("sbar_usecsqc", "1");\r
36 \r
37         gametype = 0;\r
38 \r
39         gps_start = world;\r
40 \r
41         databuf = buf_create();\r
42         for(i = 0; i < maxclients; ++i)\r
43                 bufstr_set(databuf, DATABUF_PING + i, "N/A");\r
44 }\r
45 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)\r
46 void CSQC_Shutdown(void)\r
47 {\r
48         entity next;\r
49         \r
50         buf_del(databuf);\r
51 }\r
52 \r
53 // CSQC_ConsoleCommand : Used to parse commands in the console that have been registered with the "registercmd" function\r
54 // Return value should be 1 if CSQC handled the command, otherwise return 0 to have the engine handle it.\r
55 float CSQC_ConsoleCommand(string strMessage)\r
56 {\r
57         local float nReturn;\r
58                 nReturn = FALSE;\r
59                 \r
60         // Tokenize String\r
61         tokenize(strMessage);\r
62         \r
63         // Acquire Command\r
64         local string strCmd;\r
65         strCmd = argv(0);\r
66 \r
67         /*if(strCmd == "ctf_menu") {\r
68                 ctf_menu_show();\r
69                 nReturn = TRUE;\r
70                 } else*/\r
71         if(strCmd == "ons_map") {\r
72                 Cmd_ons_map();\r
73                 nReturn = TRUE;\r
74         }\r
75         \r
76         return nReturn;\r
77 }\r
78 // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client.\r
79 // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine.\r
80 // All keys are in ascii.\r
81 // bInputType = 0 is key pressed, 1 is key released, 2 is mouse input.\r
82 // In the case of keyboard input, nPrimary is the ascii code, and nSecondary is 0.\r
83 // In the case of mouse input, nPrimary is xdelta, nSecondary is ydelta.\r
84 float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)\r
85 {\r
86         local float bSkipKey;\r
87         bSkipKey = false;\r
88         if(menu_visible)\r
89                 if(menu_action(bInputType, nPrimary, nSecondary))\r
90                         return TRUE;\r
91         return bSkipKey;\r
92 }\r
93 \r
94 // END REQUIRED CSQC FUNCTIONS\r
95 // --------------------------------------------------------------------------\r
96 \r
97 // --------------------------------------------------------------------------\r
98 // BEGIN OPTIONAL CSQC FUNCTIONS\r
99 \r
100 void ReadPings()\r
101 {\r
102         float plnum, ping;\r
103         for(plnum = ReadByte(); plnum != 0; plnum = ReadByte())\r
104         {\r
105                 ping = ReadShort();\r
106                 bufstr_set(databuf, DATABUF_PING + plnum-1, ftos(ping));\r
107         }\r
108 }\r
109 \r
110 void ReadONS(float bIsNewEntity)\r
111 {\r
112         using_gps = true;\r
113                         \r
114         self.origin_x = ReadCoord();\r
115         self.origin_y = ReadCoord();\r
116         self.angles_y = ReadCoord();\r
117         self.origin_z = self.angles_x = self.angles_z = 0;\r
118 \r
119         if(bIsNewEntity)\r
120         {\r
121                 //print(strcat("Adding entity: ", ftos(self.sv_entnum), "\n"));\r
122                 self.chain = gps_start;\r
123                 gps_start = self;\r
124         }\r
125 }\r
126 \r
127 // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.\r
128 // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.\r
129 void(float bIsNewEntity) CSQC_Ent_Update =\r
130 {\r
131         float tmp, plnum, msg;\r
132         self.enttype = ReadByte();\r
133         if(self.enttype == ENT_CLIENT_ENTCS)\r
134         {\r
135                 self.sv_entnum = ReadByte()-1;\r
136 \r
137                 for(msg = ReadByte(); msg != ENTCS_MSG_END; msg = ReadByte())\r
138                 {\r
139                         switch(msg)\r
140                         {\r
141                         case ENTCS_MSG_ONS: ReadONS(bIsNewEntity); break;\r
142                         default:\r
143                                 error("unknown ENTCS_MSG type\n");\r
144                         };\r
145                 }\r
146         }\r
147         else\r
148                 error("unknown entity type in CSQC_Ent_Update\n");\r
149         \r
150 };\r
151 // CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed.  Essentially call remove(self) as well.\r
152 void CSQC_Ent_Remove()\r
153 {\r
154         if(self.enttype == ENT_CLIENT_ENTCS)\r
155         {\r
156                 if(using_gps) //gametype == GAME_ONSLAUGHT)\r
157                 {\r
158                         if(gps_start == self)\r
159                                 gps_start = self.chain;\r
160                         else\r
161                         {\r
162                                 local entity ent;\r
163                                 ent = gps_start;\r
164                         \r
165                                 while(ent.chain != self && ent.chain != world)\r
166                                         ent = ent.chain;\r
167                                 if(ent.chain == self)\r
168                                         ent.chain = self.chain;\r
169                         }\r
170                 }\r
171         }\r
172         remove(self);\r
173 }\r
174 \r
175 void Gamemode_Init()\r
176 {\r
177         local string mapinfo, infoline;\r
178         local float len;\r
179         local float file;\r
180         local vector mi_min, mi_max;\r
181 \r
182         draw_enginesbar = true;\r
183         gametype = cvar("gametype");\r
184         if(gametype == GAME_ONSLAUGHT) {\r
185                 if(!strcasecmp(substring(mapname, 0, 5), "maps/"))\r
186                         minimapname = substring(mapname, 5, 999);\r
187                 else\r
188                         minimapname = mapname;\r
189                 len = strlen(minimapname);\r
190                 if(!strcasecmp(substring(minimapname, len-4, 4), ".bsp"))\r
191                         minimapname = substring(minimapname, 0, len-4);\r
192                 \r
193                 mapinfo = strcat("maps/", minimapname, ".info");\r
194                 minimapname = strzone(strcat("gfx/", minimapname, "_mini.tga"));\r
195 \r
196                 mi_min = world.mins;\r
197                 mi_max = world.maxs;\r
198                 \r
199                 file = fopen(mapinfo, FILE_READ);\r
200                 if(file >= 0) {\r
201                         while((infoline = fgets(file))) {\r
202                                 if(!strncasecmp(infoline, "mins", 4)) {\r
203                                         mi_min = stov(substring(infoline, 5, 999));\r
204                                 } else if(!strncasecmp(infoline, "maxs", 4)) {\r
205                                         mi_max = stov(substring(infoline, 5, 999));\r
206                                 } else if(strncasecmp(infoline, "//", 2)) { // don't print comment-style lines\r
207                                         print(strcat("mapinfo: ", infoline, "\n"));\r
208                                 }\r
209                         }\r
210                 } else {\r
211                         print(strcat("^1Error: ^7Mapinfo file '", mapinfo, "' missing! Minimap will be screwed.\n"));\r
212                 }\r
213                 fclose(file);\r
214 \r
215                 print(strcat("Mins: ", vtos(mi_min), "    Maxs: ", vtos(mi_max), "\n"));\r
216                 \r
217                 mi_center = (mi_min + mi_max) * 0.5;\r
218                 mi_scale = mi_max - mi_min;\r
219                 \r
220                 \r
221                 print(strcat("Using ", minimapname, " as minimap.\n"));\r
222                 precache_pic(minimapname);\r
223                 precache_pic("gfx/ons-cp-neutral.tga");\r
224                 precache_pic("gfx/ons-cp-red.tga");\r
225                 precache_pic("gfx/ons-cp-blue.tga");\r
226                 precache_pic("gfx/ons-frame.tga");\r
227                 precache_pic("gfx/ons-frame-team.tga");\r
228         } else if(gametype == GAME_KEYHUNT) {\r
229                 precache_pic("gfx/sb_key_carrying");\r
230                 precache_pic("gfx/sb_key_carrying_outline");\r
231                 draw_enginesbar = false;\r
232         }\r
233 }\r
234 // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided.  To execute standard behavior, simply execute localcmd with the string.\r
235 void CSQC_Parse_StuffCmd(string strMessage)\r
236 {\r
237         localcmd(strMessage);\r
238         // watch for gametype changes!\r
239         if(gametype != cvar("gametype"))\r
240         {\r
241                 Gamemode_Init();\r
242         }\r
243 }\r
244 // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided.  To execute standard behavior, simply execute print with the string.\r
245 void CSQC_Parse_Print(string strMessage)\r
246 {\r
247         print(strMessage);\r
248 }\r
249 // CSQC_Parse_CenterPrint : Provides the centerprint string in the first parameter that the server provided.  To execute standard behavior, simply execute cprint with the string.\r
250 void CSQC_Parse_CenterPrint(string strMessage)\r
251 {\r
252         cprint(strMessage);\r
253 }\r
254 // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.\r
255 // You must ALWAYS first acquire the temporary ID, which is sent as a byte.\r
256 // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.\r
257 float CSQC_Parse_TempEntity()\r
258 {\r
259         local float bHandled;\r
260                 bHandled  = true;\r
261         // Acquire TE ID\r
262         local float nTEID;\r
263                 nTEID = ReadByte();\r
264                 \r
265         switch(nTEID)\r
266         {\r
267                 case TE_CSQC_PING:\r
268                         ReadPings();\r
269                         bHandled = true;\r
270                         break;\r
271                 //case TE_GUNSHOT:\r
272                 //      Do something cool with TE_GUNSHOT!\r
273                 //      break;\r
274                 default:\r
275                         // No special logic for this temporary entity; return 0 so the engine can handle it\r
276                         bHandled = false;\r
277                         break;\r
278         }\r
279                 \r
280         return bHandled;\r
281 }\r