summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/sv_user.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-11 15:34:30 -0500
committerFranklin Wei <git@fwei.tk>2019-07-19 22:37:40 -0400
commit5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4 (patch)
tree84406e21639529a185556a33e5de7f43cffc277b /apps/plugins/sdl/progs/quake/sv_user.c
parentb70fecf21ddc21877ec1ae7888d9c18a979e37ad (diff)
downloadrockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.tar.gz
rockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.zip
Quake!
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
Diffstat (limited to 'apps/plugins/sdl/progs/quake/sv_user.c')
-rw-r--r--apps/plugins/sdl/progs/quake/sv_user.c629
1 files changed, 629 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/sv_user.c b/apps/plugins/sdl/progs/quake/sv_user.c
new file mode 100644
index 0000000000..b3082a5918
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_user.c
@@ -0,0 +1,629 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_user.c -- server code for moving users
21
22#include "quakedef.h"
23
24edict_t *sv_player;
25
26extern cvar_t sv_friction;
27cvar_t sv_edgefriction = {"edgefriction", "2"};
28extern cvar_t sv_stopspeed;
29
30static vec3_t forward, right, up;
31
32vec3_t wishdir;
33float wishspeed;
34
35// world
36float *angles;
37float *origin;
38float *velocity;
39
40qboolean onground;
41
42usercmd_t cmd;
43
44cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8"};
45
46
47/*
48===============
49SV_SetIdealPitch
50===============
51*/
52#define MAX_FORWARD 6
53void SV_SetIdealPitch (void)
54{
55 float angleval, sinval, cosval;
56 trace_t tr;
57 vec3_t top, bottom;
58 float z[MAX_FORWARD];
59 int i, j;
60 int step, dir, steps;
61
62 if (!((int)sv_player->v.flags & FL_ONGROUND))
63 return;
64
65 angleval = sv_player->v.angles[YAW] * M_PI*2 / 360;
66 sinval = sin(angleval);
67 cosval = cos(angleval);
68
69 for (i=0 ; i<MAX_FORWARD ; i++)
70 {
71 top[0] = sv_player->v.origin[0] + cosval*(i+3)*12;
72 top[1] = sv_player->v.origin[1] + sinval*(i+3)*12;
73 top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];
74
75 bottom[0] = top[0];
76 bottom[1] = top[1];
77 bottom[2] = top[2] - 160;
78
79 tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);
80 if (tr.allsolid)
81 return; // looking at a wall, leave ideal the way is was
82
83 if (tr.fraction == 1)
84 return; // near a dropoff
85
86 z[i] = top[2] + tr.fraction*(bottom[2]-top[2]);
87 }
88
89 dir = 0;
90 steps = 0;
91 for (j=1 ; j<i ; j++)
92 {
93 step = z[j] - z[j-1];
94 if (step > -ON_EPSILON && step < ON_EPSILON)
95 continue;
96
97 if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )
98 return; // mixed changes
99
100 steps++;
101 dir = step;
102 }
103
104 if (!dir)
105 {
106 sv_player->v.idealpitch = 0;
107 return;
108 }
109
110 if (steps < 2)
111 return;
112 sv_player->v.idealpitch = -dir * sv_idealpitchscale.value;
113}
114
115
116/*
117==================
118SV_UserFriction
119
120==================
121*/
122void SV_UserFriction (void)
123{
124 float *vel;
125 float speed, newspeed, control;
126 vec3_t start, stop;
127 float friction;
128 trace_t trace;
129
130 vel = velocity;
131
132 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
133 if (!speed)
134 return;
135
136// if the leading edge is over a dropoff, increase friction
137 start[0] = stop[0] = origin[0] + vel[0]/speed*16;
138 start[1] = stop[1] = origin[1] + vel[1]/speed*16;
139 start[2] = origin[2] + sv_player->v.mins[2];
140 stop[2] = start[2] - 34;
141
142 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);
143
144 if (trace.fraction == 1.0)
145 friction = sv_friction.value*sv_edgefriction.value;
146 else
147 friction = sv_friction.value;
148
149// apply friction
150 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
151 newspeed = speed - host_frametime*control*friction;
152
153 if (newspeed < 0)
154 newspeed = 0;
155 newspeed /= speed;
156
157 vel[0] = vel[0] * newspeed;
158 vel[1] = vel[1] * newspeed;
159 vel[2] = vel[2] * newspeed;
160}
161
162/*
163==============
164SV_Accelerate
165==============
166*/
167cvar_t sv_maxspeed = {"sv_maxspeed", "320", false, true};
168cvar_t sv_accelerate = {"sv_accelerate", "10"};
169#if 0
170void SV_Accelerate (vec3_t wishvel)
171{
172 int i;
173 float addspeed, accelspeed;
174 vec3_t pushvec;
175
176 if (wishspeed == 0)
177 return;
178
179 VectorSubtract (wishvel, velocity, pushvec);
180 addspeed = VectorNormalize (pushvec);
181
182 accelspeed = sv_accelerate.value*host_frametime*addspeed;
183 if (accelspeed > addspeed)
184 accelspeed = addspeed;
185
186 for (i=0 ; i<3 ; i++)
187 velocity[i] += accelspeed*pushvec[i];
188}
189#endif
190void SV_Accelerate (void)
191{
192 int i;
193 float addspeed, accelspeed, currentspeed;
194
195 currentspeed = DotProduct (velocity, wishdir);
196 addspeed = wishspeed - currentspeed;
197 if (addspeed <= 0)
198 return;
199 accelspeed = sv_accelerate.value*host_frametime*wishspeed;
200 if (accelspeed > addspeed)
201 accelspeed = addspeed;
202
203 for (i=0 ; i<3 ; i++)
204 velocity[i] += accelspeed*wishdir[i];
205}
206
207void SV_AirAccelerate (vec3_t wishveloc)
208{
209 int i;
210 float addspeed, wishspd, accelspeed, currentspeed;
211
212 wishspd = VectorNormalize (wishveloc);
213 if (wishspd > 30)
214 wishspd = 30;
215 currentspeed = DotProduct (velocity, wishveloc);
216 addspeed = wishspd - currentspeed;
217 if (addspeed <= 0)
218 return;
219// accelspeed = sv_accelerate.value * host_frametime;
220 accelspeed = sv_accelerate.value*wishspeed * host_frametime;
221 if (accelspeed > addspeed)
222 accelspeed = addspeed;
223
224 for (i=0 ; i<3 ; i++)
225 velocity[i] += accelspeed*wishveloc[i];
226}
227
228
229void DropPunchAngle (void)
230{
231 float len;
232
233 len = VectorNormalize (sv_player->v.punchangle);
234
235 len -= 10*host_frametime;
236 if (len < 0)
237 len = 0;
238 VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle);
239}
240
241/*
242===================
243SV_WaterMove
244
245===================
246*/
247void SV_WaterMove (void)
248{
249 int i;
250 vec3_t wishvel;
251 float speed, newspeed, wishspeed, addspeed, accelspeed;
252
253//
254// user intentions
255//
256 AngleVectors (sv_player->v.v_angle, forward, right, up);
257
258 for (i=0 ; i<3 ; i++)
259 wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
260
261 if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
262 wishvel[2] -= 60; // drift towards bottom
263 else
264 wishvel[2] += cmd.upmove;
265
266 wishspeed = Length(wishvel);
267 if (wishspeed > sv_maxspeed.value)
268 {
269 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
270 wishspeed = sv_maxspeed.value;
271 }
272 wishspeed *= 0.7;
273
274//
275// water friction
276//
277 speed = Length (velocity);
278 if (speed)
279 {
280 newspeed = speed - host_frametime * speed * sv_friction.value;
281 if (newspeed < 0)
282 newspeed = 0;
283 VectorScale (velocity, newspeed/speed, velocity);
284 }
285 else
286 newspeed = 0;
287
288//
289// water acceleration
290//
291 if (!wishspeed)
292 return;
293
294 addspeed = wishspeed - newspeed;
295 if (addspeed <= 0)
296 return;
297
298 VectorNormalizeNoRet (wishvel);
299 accelspeed = sv_accelerate.value * wishspeed * host_frametime;
300 if (accelspeed > addspeed)
301 accelspeed = addspeed;
302
303 for (i=0 ; i<3 ; i++)
304 velocity[i] += accelspeed * wishvel[i];
305}
306
307void SV_WaterJump (void)
308{
309 if (sv.time > sv_player->v.teleport_time
310 || !sv_player->v.waterlevel)
311 {
312 sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;
313 sv_player->v.teleport_time = 0;
314 }
315 sv_player->v.velocity[0] = sv_player->v.movedir[0];
316 sv_player->v.velocity[1] = sv_player->v.movedir[1];
317}
318
319
320/*
321===================
322SV_AirMove
323
324===================
325*/
326void SV_AirMove (void)
327{
328 int i;
329 vec3_t wishvel;
330 float fmove, smove;
331
332 AngleVectors (sv_player->v.angles, forward, right, up);
333
334 fmove = cmd.forwardmove;
335 smove = cmd.sidemove;
336
337// hack to not let you back into teleporter
338 if (sv.time < sv_player->v.teleport_time && fmove < 0)
339 fmove = 0;
340
341 for (i=0 ; i<3 ; i++)
342 wishvel[i] = forward[i]*fmove + right[i]*smove;
343
344 if ( (int)sv_player->v.movetype != MOVETYPE_WALK)
345 wishvel[2] = cmd.upmove;
346 else
347 wishvel[2] = 0;
348
349 VectorCopy (wishvel, wishdir);
350 wishspeed = VectorNormalize(wishdir);
351 if (wishspeed > sv_maxspeed.value)
352 {
353 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
354 wishspeed = sv_maxspeed.value;
355 }
356
357 if ( sv_player->v.movetype == MOVETYPE_NOCLIP)
358 { // noclip
359 VectorCopy (wishvel, velocity);
360 }
361 else if ( onground )
362 {
363 SV_UserFriction ();
364 SV_Accelerate ();
365 }
366 else
367 { // not on ground, so little effect on velocity
368 SV_AirAccelerate (wishvel);
369 }
370}
371
372/*
373===================
374SV_ClientThink
375
376the move fields specify an intended velocity in pix/sec
377the angle fields specify an exact angular motion in degrees
378===================
379*/
380void SV_ClientThink (void)
381{
382 vec3_t v_angle;
383
384 if (sv_player->v.movetype == MOVETYPE_NONE)
385 return;
386
387 onground = (int)sv_player->v.flags & FL_ONGROUND;
388
389 origin = sv_player->v.origin;
390 velocity = sv_player->v.velocity;
391
392 DropPunchAngle ();
393
394//
395// if dead, behave differently
396//
397 if (sv_player->v.health <= 0)
398 return;
399
400//
401// angles
402// show 1/3 the pitch angle and all the roll angle
403 cmd = host_client->cmd;
404 angles = sv_player->v.angles;
405
406 VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);
407 angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
408 if (!sv_player->v.fixangle)
409 {
410 angles[PITCH] = -v_angle[PITCH]/3;
411 angles[YAW] = v_angle[YAW];
412 }
413
414 if ( (int)sv_player->v.flags & FL_WATERJUMP )
415 {
416 SV_WaterJump ();
417 return;
418 }
419//
420// walk
421//
422 if ( (sv_player->v.waterlevel >= 2)
423 && (sv_player->v.movetype != MOVETYPE_NOCLIP) )
424 {
425 SV_WaterMove ();
426 return;
427 }
428
429 SV_AirMove ();
430}
431
432
433/*
434===================
435SV_ReadClientMove
436===================
437*/
438void SV_ReadClientMove (usercmd_t *move)
439{
440 int i;
441 vec3_t angle;
442 int bits;
443
444// read ping time
445 host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
446 = sv.time - MSG_ReadFloat ();
447 host_client->num_pings++;
448
449// read current angles
450 for (i=0 ; i<3 ; i++)
451 angle[i] = MSG_ReadAngle ();
452
453 VectorCopy (angle, host_client->edict->v.v_angle);
454
455// read movement
456 move->forwardmove = MSG_ReadShort ();
457 move->sidemove = MSG_ReadShort ();
458 move->upmove = MSG_ReadShort ();
459
460// read buttons
461 bits = MSG_ReadByte ();
462 host_client->edict->v.button0 = bits & 1;
463 host_client->edict->v.button2 = (bits & 2)>>1;
464
465 i = MSG_ReadByte ();
466 if (i)
467 host_client->edict->v.impulse = i;
468
469#ifdef QUAKE2
470// read light level
471 host_client->edict->v.light_level = MSG_ReadByte ();
472#endif
473}
474
475/*
476===================
477SV_ReadClientMessage
478
479Returns false if the client should be killed
480===================
481*/
482qboolean SV_ReadClientMessage (void)
483{
484 int ret;
485 int cmd;
486 char *s;
487
488 do
489 {
490nextmsg:
491 ret = NET_GetMessage (host_client->netconnection);
492 if (ret == -1)
493 {
494 Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
495 return false;
496 }
497 if (!ret)
498 return true;
499
500 MSG_BeginReading ();
501
502 while (1)
503 {
504 if (!host_client->active)
505 return false; // a command caused an error
506
507 if (msg_badread)
508 {
509 Sys_Printf ("SV_ReadClientMessage: badread\n");
510 return false;
511 }
512
513 cmd = MSG_ReadChar ();
514
515 switch (cmd)
516 {
517 case -1:
518 goto nextmsg; // end of message
519
520 default:
521 Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
522 return false;
523
524 case clc_nop:
525// Sys_Printf ("clc_nop\n");
526 break;
527
528 case clc_stringcmd:
529 s = MSG_ReadString ();
530 if (host_client->privileged)
531 ret = 2;
532 else
533 ret = 0;
534 if (Q_strncasecmp(s, "status", 6) == 0)
535 ret = 1;
536 else if (Q_strncasecmp(s, "god", 3) == 0)
537 ret = 1;
538 else if (Q_strncasecmp(s, "notarget", 8) == 0)
539 ret = 1;
540 else if (Q_strncasecmp(s, "fly", 3) == 0)
541 ret = 1;
542 else if (Q_strncasecmp(s, "name", 4) == 0)
543 ret = 1;
544 else if (Q_strncasecmp(s, "noclip", 6) == 0)
545 ret = 1;
546 else if (Q_strncasecmp(s, "say", 3) == 0)
547 ret = 1;
548 else if (Q_strncasecmp(s, "say_team", 8) == 0)
549 ret = 1;
550 else if (Q_strncasecmp(s, "tell", 4) == 0)
551 ret = 1;
552 else if (Q_strncasecmp(s, "color", 5) == 0)
553 ret = 1;
554 else if (Q_strncasecmp(s, "kill", 4) == 0)
555 ret = 1;
556 else if (Q_strncasecmp(s, "pause", 5) == 0)
557 ret = 1;
558 else if (Q_strncasecmp(s, "spawn", 5) == 0)
559 ret = 1;
560 else if (Q_strncasecmp(s, "begin", 5) == 0)
561 ret = 1;
562 else if (Q_strncasecmp(s, "prespawn", 8) == 0)
563 ret = 1;
564 else if (Q_strncasecmp(s, "kick", 4) == 0)
565 ret = 1;
566 else if (Q_strncasecmp(s, "ping", 4) == 0)
567 ret = 1;
568 else if (Q_strncasecmp(s, "give", 4) == 0)
569 ret = 1;
570 else if (Q_strncasecmp(s, "ban", 3) == 0)
571 ret = 1;
572 if (ret == 2)
573 Cbuf_InsertText (s);
574 else if (ret == 1)
575 Cmd_ExecuteString (s, src_client);
576 else
577 Con_DPrintf("%s tried to %s\n", host_client->name, s);
578 break;
579
580 case clc_disconnect:
581// Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
582 return false;
583
584 case clc_move:
585 SV_ReadClientMove (&host_client->cmd);
586 break;
587 }
588 }
589 } while (ret == 1);
590
591 return true;
592}
593
594
595/*
596==================
597SV_RunClients
598==================
599*/
600void SV_RunClients (void)
601{
602 int i;
603
604 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
605 {
606 if (!host_client->active)
607 continue;
608
609 sv_player = host_client->edict;
610
611 if (!SV_ReadClientMessage ())
612 {
613 SV_DropClient (false); // client misbehaved...
614 continue;
615 }
616
617 if (!host_client->spawned)
618 {
619 // clear client movement until a new packet is received
620 memset (&host_client->cmd, 0, sizeof(host_client->cmd));
621 continue;
622 }
623
624// always pause in single player if in console or menus
625 if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
626 SV_ClientThink ();
627 }
628}
629