]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/i_linux.c
Initial revision
[theoddone33/hheretic.git] / base / i_linux.c
1 //**************************************************************************
2 //**
3 //** $Id$
4 //**
5 //**************************************************************************
6
7
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <sys/time.h>
11 #include "doomdef.h"
12 #include "r_local.h"
13 #include "p_local.h"    // for P_AproxDistance
14 #include "sounds.h"
15 #include "i_sound.h"
16 #include "soundst.h"
17
18 // Macros
19
20 #define stricmp strcasecmp
21 #define DEFAULT_ARCHIVEPATH     "o:\\sound\\archive\\"
22 #define PRIORITY_MAX_ADJUST 10
23 #define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
24
25 #define KEY_LSHIFT      0xfe
26
27 #define KEY_INS         (0x80+0x52)
28 #define KEY_DEL         (0x80+0x53)
29 #define KEY_PGUP        (0x80+0x49)
30 #define KEY_PGDN        (0x80+0x51)
31 #define KEY_HOME        (0x80+0x47)
32 #define KEY_END         (0x80+0x4f)
33
34 extern void **lumpcache;
35
36 extern void I_StartupMouse();
37 extern void I_ShutdownGraphics();
38
39 int i_Vector;
40 externdata_t *i_ExternData;
41 boolean useexterndriver;
42
43 // Function Declarations
44 void I_StopSong(int handle);
45 void I_UnRegisterSong(int handle);
46 int I_RegisterSong (void *data);
47 void I_PlaySong(int handle, boolean looping);
48 int I_SoundIsPlaying (int handle);
49 void I_StopSound (int handle);
50 int I_GetSfxLumpNum (sfxinfo_t *sound);
51 int I_StartSound( int id, void* data, int vol, int sep, int pitch, int priority);
52 void I_PauseSong(int handle);
53 void I_ResumeSong(int handle);
54 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
55 void I_StartupSound (void);
56 void I_SetChannels(int channels);
57 void I_SetMusicVolume(int volume);
58 void I_ShutdownSound (void);
59
60 /*
61 ===============================================================================
62
63                 MUSIC & SFX API
64
65 ===============================================================================
66 */
67
68 //static channel_t channel[MAX_CHANNELS];
69
70 //static int rs; //the current registered song.
71 //int mus_song = -1;
72 //int mus_lumpnum;
73 //void *mus_sndptr;
74 //byte *soundCurve;
75
76 extern sfxinfo_t S_sfx[];
77 extern musicinfo_t S_music[];
78
79 static channel_t Channel[MAX_CHANNELS];
80 static int RegisteredSong; //the current registered song.
81 static int NextCleanup;
82 static boolean MusicPaused;
83 static int Mus_Song = -1;
84 static int Mus_LumpNum;
85 static void *Mus_SndPtr;
86 static byte *SoundCurve;
87
88 extern int snd_MusicDevice;
89 extern int snd_SfxDevice;
90 extern int snd_MaxVolume;
91 extern int snd_MusicVolume;
92 extern int snd_Channels;
93
94 extern int startepisode;
95 extern int startmap;
96
97 int AmbChan;
98
99 boolean S_StopSoundID(int sound_id, int priority);
100
101 //==========================================================================
102 //
103 // S_Start
104 //
105 //==========================================================================
106
107 void S_Start(void)
108 {
109         int i;
110
111         S_StartSong((gameepisode-1)*9 + gamemap-1, true);
112
113         //stop all sounds
114         for(i=0; i < snd_Channels; i++)
115         {
116                 if(Channel[i].handle)
117                 {
118                         S_StopSound(Channel[i].mo);
119                 }
120         }
121         memset(Channel, 0, 8*sizeof(channel_t));
122 }
123
124 //==========================================================================
125 //
126 // S_StartSong
127 //
128 //==========================================================================
129
130 void S_StartSong(int song, boolean loop)
131 {
132         if(song == Mus_Song)
133         { // don't replay an old song
134                 return;
135         }
136         if(RegisteredSong)
137         {
138                 I_StopSong(RegisteredSong);
139                 I_UnRegisterSong(RegisteredSong);
140                 Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
141         }
142         if(song < mus_e1m1 || song > NUMMUSIC)
143         {
144                 return;
145         }
146         Mus_LumpNum = W_GetNumForName(S_music[song].name);
147         Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
148         RegisteredSong = I_RegisterSong(Mus_SndPtr);
149         I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
150         Mus_Song = song;
151 }
152
153 //==========================================================================
154 //
155 // S_StartSound
156 //
157 //==========================================================================
158
159 void S_StartSound(mobj_t *origin, int sound_id)
160 {
161         int dist, vol;
162         int i;
163         int priority;
164         int sep;
165         int angle;
166         int absx;
167         int absy;
168
169         static int sndcount = 0;
170         int chan;
171
172         if(sound_id==0 || snd_MaxVolume == 0)
173                 return;
174         if(origin == NULL)
175         {
176         //      origin = players[consoleplayer].mo;
177         }
178
179 // calculate the distance before other stuff so that we can throw out
180 // sounds that are beyond the hearing range.
181         if (origin)
182         {
183                 absx = abs(origin->x-players[consoleplayer].mo->x);
184                 absy = abs(origin->y-players[consoleplayer].mo->y);
185         }
186         else
187                 absx = absy = 0;
188         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
189         dist >>= FRACBITS;
190 //  dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS;
191
192         if(dist >= MAX_SND_DIST)
193         {
194 //      dist = MAX_SND_DIST - 1;
195           return; //sound is beyond the hearing range...
196         }
197         if(dist < 0)
198         {
199                 dist = 0;
200         }
201         priority = S_sfx[sound_id].priority;
202         priority *= (10 - (dist/160));
203         if(!S_StopSoundID(sound_id, priority))
204         {
205                 return; // other sounds have greater priority
206         }
207         for(i=0; i<snd_Channels; i++)
208         {
209                 if(!origin || origin->player)
210                 {
211                         i = snd_Channels;
212                         break; // let the player have more than one sound.
213                 }
214                 if(origin == Channel[i].mo)
215                 { // only allow other mobjs one sound
216                         S_StopSound(Channel[i].mo);
217                         break;
218                 }
219         }
220         if(i >= snd_Channels)
221         {
222                 if(sound_id >= sfx_wind)
223                 {
224                         if(AmbChan != -1 && S_sfx[sound_id].priority <=
225                                 S_sfx[Channel[AmbChan].sound_id].priority)
226                         {
227                                 return; //ambient channel already in use
228                         }
229                         else
230                         {
231                                 AmbChan = -1;
232                         }
233                 }
234                 for(i=0; i<snd_Channels; i++)
235                 {
236                         if(Channel[i].mo == NULL)
237                         {
238                                 break;
239                         }
240                 }
241                 if(i >= snd_Channels)
242                 {
243                         //look for a lower priority sound to replace.
244                         sndcount++;
245                         if(sndcount >= snd_Channels)
246                         {
247                                 sndcount = 0;
248                         }
249                         for(chan=0; chan < snd_Channels; chan++)
250                         {
251                                 i = (sndcount+chan)%snd_Channels;
252                                 if(priority >= Channel[i].priority)
253                                 {
254                                         chan = -1; //denote that sound should be replaced.
255                                         break;
256                                 }
257                         }
258                         if(chan != -1)
259                         {
260                                 return; //no free channels.
261                         }
262                         else //replace the lower priority sound.
263                         {
264                                 if(Channel[i].handle)
265                                 {
266                                         if(I_SoundIsPlaying(Channel[i].handle))
267                                         {
268                                                 I_StopSound(Channel[i].handle);
269                                         }
270                                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
271                                         {
272                                                 S_sfx[Channel[i].sound_id].usefulness--;
273                                         }
274
275                                         if(AmbChan == i)
276                                         {
277                                                 AmbChan = -1;
278                                         }
279                                 }
280                         }
281                 }
282         }
283         if(S_sfx[sound_id].lumpnum == 0)
284         {
285                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
286         }
287         if(S_sfx[sound_id].snd_ptr == NULL)
288         {
289                 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
290                         PU_SOUND);
291         }
292
293         // calculate the volume based upon the distance from the sound origin.
294 //      vol = (snd_MaxVolume*16 + dist*(-snd_MaxVolume*16)/MAX_SND_DIST)>>9;
295         vol = SoundCurve[dist];
296
297         if(!origin || origin == players[consoleplayer].mo)
298         {
299                 sep = 128;
300         }
301         else
302         {
303                 angle = R_PointToAngle2(players[consoleplayer].mo->x,
304 //                        players[consoleplayer].mo->y, Channel[i].mo->x, Channel[i].mo->y);
305                         players[displayplayer].mo->y, origin->x, origin->y);
306
307                 angle = (angle-viewangle)>>24;
308                 sep = angle*2-128;
309                 if(sep < 64)
310                         sep = -sep;
311                 if(sep > 192)
312                         sep = 512-sep;
313         }
314
315         Channel[i].pitch = (byte)(127+(M_Random()&7)-(M_Random()&7));
316         Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol, sep, Channel[i].pitch, 0);
317         Channel[i].mo = origin;
318         Channel[i].sound_id = sound_id;
319         Channel[i].priority = priority;
320         if(sound_id >= sfx_wind)
321         {
322                 AmbChan = i;
323         }
324         if(S_sfx[sound_id].usefulness == -1)
325         {
326                 S_sfx[sound_id].usefulness = 1;
327         }
328         else
329         {
330                 S_sfx[sound_id].usefulness++;
331         }
332 }
333
334 //==========================================================================
335 //
336 // S_StartSoundAtVolume
337 //
338 //==========================================================================
339 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
340 {
341         int i;
342
343         if(sound_id == 0 || snd_MaxVolume == 0)
344                 return;
345         if(origin == NULL)
346         {
347                 origin = players[displayplayer].mo;
348         }
349
350         if(volume == 0)
351         {
352                 return;
353         }
354         volume = (volume*(snd_MaxVolume+1)*8)>>7;
355
356 // no priority checking, as ambient sounds would be the LOWEST.
357         for(i=0; i<snd_Channels; i++)
358         {
359                 if(Channel[i].mo == NULL)
360                 {
361                         break;
362                 }
363         }
364         if(i >= snd_Channels)
365         {
366                 return;
367         }
368         if(S_sfx[sound_id].lumpnum == 0)
369         {
370                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
371         }
372         if(S_sfx[sound_id].snd_ptr == NULL)
373         {
374                 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
375                         PU_SOUND);
376         }
377         Channel[i].pitch = (byte)(127-(M_Random()&3)+(M_Random()&3));
378         Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, volume, 128, Channel[i].pitch, 0);
379         Channel[i].mo = origin;
380         Channel[i].sound_id = sound_id;
381         Channel[i].priority = 1; //super low priority.
382         if(S_sfx[sound_id].usefulness == -1)
383         {
384                 S_sfx[sound_id].usefulness = 1;
385         }
386         else
387         {
388                 S_sfx[sound_id].usefulness++;
389         }
390 }
391 //==========================================================================
392 //
393 // S_StopSoundID
394 //
395 //==========================================================================
396
397 boolean S_StopSoundID(int sound_id, int priority)
398 {
399         int i;
400         int lp; //least priority
401         int found;
402
403         if(S_sfx[sound_id].numchannels == -1)
404         {
405                 return(true);
406         }
407         lp = -1; //denote the argument sound_id
408         found = 0;
409         for(i=0; i<snd_Channels; i++)
410         {
411                 if(Channel[i].sound_id == sound_id && Channel[i].mo)
412                 {
413                         found++; //found one.  Now, should we replace it??
414                         if(priority >= Channel[i].priority)
415                         { // if we're gonna kill one, then this'll be it
416                                 lp = i;
417                                 priority = Channel[i].priority;
418                         }
419                 }
420         }
421         if(found < S_sfx[sound_id].numchannels)
422         {
423                 return(true);
424         }
425         else if(lp == -1)
426         {
427                 return(false); // don't replace any sounds
428         }
429         if(Channel[lp].handle)
430         {
431                 if(I_SoundIsPlaying(Channel[lp].handle))
432                 {
433                         I_StopSound(Channel[lp].handle);
434                 }
435                 if(S_sfx[Channel[lp].sound_id].usefulness > 0)
436                 {
437                         S_sfx[Channel[lp].sound_id].usefulness--;
438                 }
439                 Channel[lp].mo = NULL;
440         }
441         return(true);
442 }
443
444 //==========================================================================
445 //
446 // S_StopSound
447 //
448 //==========================================================================
449
450 void S_StopSound(mobj_t *origin)
451 {
452         int i;
453
454         for(i=0;i<snd_Channels;i++)
455         {
456                 if(Channel[i].mo == origin)
457                 {
458                         I_StopSound(Channel[i].handle);
459                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
460                         {
461                                 S_sfx[Channel[i].sound_id].usefulness--;
462                         }
463                         Channel[i].handle = 0;
464                         Channel[i].mo = NULL;
465                         if(AmbChan == i)
466                         {
467                                 AmbChan = -1;
468                         }
469                 }
470         }
471 }
472
473 //==========================================================================
474 //
475 // S_SoundLink
476 //
477 //==========================================================================
478
479 void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
480 {
481         int i;
482
483         for(i=0;i<snd_Channels;i++)
484         {
485                 if(Channel[i].mo == oldactor)
486                         Channel[i].mo = newactor;
487         }
488 }
489
490 //==========================================================================
491 //
492 // S_PauseSound
493 //
494 //==========================================================================
495
496 void S_PauseSound(void)
497 {
498         I_PauseSong(RegisteredSong);
499 }
500
501 //==========================================================================
502 //
503 // S_ResumeSound
504 //
505 //==========================================================================
506
507 void S_ResumeSound(void)
508 {
509         I_ResumeSong(RegisteredSong);
510 }
511
512 //==========================================================================
513 //
514 // S_UpdateSounds
515 //
516 //==========================================================================
517
518 void S_UpdateSounds(mobj_t *listener)
519 {
520         int i, dist, vol;
521         int angle;
522         int sep;
523         int priority;
524         int absx;
525         int absy;
526
527         listener = players[consoleplayer].mo;
528         if(snd_MaxVolume == 0)
529         {
530                 return;
531         }
532
533         if(NextCleanup < gametic)
534         {
535                 for(i = 0; i < NUMSFX; i++)
536                 {
537                         if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
538                         {
539                                 if(lumpcache[S_sfx[i].lumpnum])
540                                 {
541                                         if(((memblock_t *)((byte*) (lumpcache[S_sfx[i].lumpnum])-
542                                                 sizeof(memblock_t)))->id == 0x1d4a11)
543                                         { // taken directly from the Z_ChangeTag macro
544                                                 Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum],
545                                                         PU_CACHE); 
546                                         }
547                                 }
548                                 S_sfx[i].usefulness = -1;
549                                 S_sfx[i].snd_ptr = NULL;
550                         }
551                 }
552                 // Note, heretic does this every second (gametic+35)
553                 NextCleanup = gametic+35*30; // every 30 seconds
554         }
555         for(i=0;i<snd_Channels;i++)
556         {
557                 if(!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
558                 {
559                         continue;
560                 }
561                 if(!I_SoundIsPlaying(Channel[i].handle))
562                 {
563                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
564                         {
565                                 S_sfx[Channel[i].sound_id].usefulness--;
566                         }
567                         Channel[i].handle = 0;
568                         Channel[i].mo = NULL;
569                         Channel[i].sound_id = 0;
570                         if(AmbChan == i)
571                         {
572                                 AmbChan = -1;
573                         }
574                 }
575                 if(Channel[i].mo == NULL || Channel[i].sound_id == 0
576                         || Channel[i].mo == listener)
577                 {
578                         continue;
579                 }
580                 else
581                 {
582                         absx = abs(Channel[i].mo->x-listener->x);
583                         absy = abs(Channel[i].mo->y-listener->y);
584                         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
585                         dist >>= FRACBITS;
586
587                         if(dist >= MAX_SND_DIST)
588                         {
589                                 S_StopSound(Channel[i].mo);
590                                 continue;
591                         }
592                         if(dist < 0)
593                         {
594                                 dist = 0;
595                         }
596                         vol = SoundCurve[dist];
597                         angle = R_PointToAngle2(listener->x, listener->y,
598                                         Channel[i].mo->x, Channel[i].mo->y);
599                         angle = (angle-viewangle)>>24;
600                         sep = angle*2-128;
601                         if(sep < 64)
602                                 sep = -sep;
603                         if(sep > 192)
604                                 sep = 512-sep;
605                         I_UpdateSoundParams(Channel[i].handle, vol, sep, Channel[i].pitch);
606                         priority = S_sfx[Channel[i].sound_id].priority;
607                         priority *= PRIORITY_MAX_ADJUST-(dist/DIST_ADJUST);
608                         Channel[i].priority = priority;
609                 }
610         }
611 }
612
613 //==========================================================================
614 //
615 // S_Init
616 //
617 //==========================================================================
618
619 void S_Init(void)
620 {
621         SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
622         I_StartupSound();
623         if(snd_Channels > 8)
624         {
625                 snd_Channels = 8;
626         }
627         I_SetChannels(snd_Channels);
628         I_SetMusicVolume(snd_MusicVolume);
629         S_SetMaxVolume(true);
630 }
631
632 //==========================================================================
633 //
634 // S_GetChannelInfo
635 //
636 //==========================================================================
637
638 void S_GetChannelInfo(SoundInfo_t *s)
639 {
640         int i;
641         ChanInfo_t *c;
642
643         s->channelCount = snd_Channels;
644         s->musicVolume = snd_MusicVolume;
645         s->soundVolume = snd_MaxVolume;
646         for(i = 0; i < snd_Channels; i++)
647         {
648                 c = &s->chan[i];
649                 c->id = Channel[i].sound_id;
650                 c->priority = Channel[i].priority;
651                 c->name = S_sfx[c->id].name;
652                 c->mo = Channel[i].mo;
653                 c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)
654                         >>FRACBITS;
655         }
656 }
657
658 void S_SetMaxVolume(boolean fullprocess)
659 {
660         int i;
661
662         if(!fullprocess)
663         {
664                 SoundCurve[0] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE))*(snd_MaxVolume*8))>>7;
665         }
666         else
667         {
668                 for(i = 0; i < MAX_SND_DIST; i++)
669                 {
670                         SoundCurve[i] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+i)*(snd_MaxVolume*8))>>7;
671                 }
672         }
673 }
674
675 //==========================================================================
676 //
677 // S_SetMusicVolume
678 //
679 //==========================================================================
680
681 void S_SetMusicVolume(void)
682 {
683         I_SetMusicVolume(snd_MusicVolume);
684         if(snd_MusicVolume == 0)
685         {
686                 I_PauseSong(RegisteredSong);
687                 MusicPaused = true;
688         }
689         else if(MusicPaused)
690         {
691                 MusicPaused = false;
692                 I_ResumeSong(RegisteredSong);
693         }
694 }
695
696 //==========================================================================
697 //
698 // S_ShutDown
699 //
700 //==========================================================================
701
702 void S_ShutDown(void)
703 {
704         extern int tsm_ID;
705         if(tsm_ID != -1)
706         {
707                 I_StopSong(RegisteredSong);
708                 I_UnRegisterSong(RegisteredSong);
709                 I_ShutdownSound();
710         }
711 }
712
713 //==================================================
714
715
716 int ticcount;
717
718 boolean novideo; // if true, stay in text mode for debugging
719
720
721 //==========================================================================
722
723
724 static long _startSec;
725
726 void I_StartupTimer(void)
727 {
728    struct timeval tv;
729     gettimeofday( &tv, 0 ); 
730     _startSec = tv.tv_sec;
731 }
732
733 //--------------------------------------------------------------------------
734 //
735 // FUNC I_GetTime
736 //
737 // Returns time in 1/35th second tics.
738 //
739 //--------------------------------------------------------------------------
740
741 int I_GetTime (void)
742 {
743     struct timeval tv;
744     gettimeofday( &tv, 0 ); 
745
746     //printf( "GT: %lx %lx\n", tv.tv_sec, tv.tv_usec );
747
748 //  ticcount = ((tv.tv_sec * 1000000) + tv.tv_usec) / 28571;
749     ticcount = ((tv.tv_sec - _startSec) * 35) + (tv.tv_usec / 28571);
750         return( ticcount );
751 }
752
753
754 /*
755 ============================================================================
756
757                                         JOYSTICK
758
759 ============================================================================
760 */
761
762 //==================================================
763 //
764 // joystick vars
765 //
766 //==================================================
767
768 extern int usejoystick;
769 boolean joystickpresent;
770 unsigned joystickx, joysticky;
771
772 // returns false if not connected
773 boolean I_ReadJoystick (void)
774 {
775     return false;
776 }
777
778
779 int     joyxl, joyxh, joyyl, joyyh;
780
781 boolean WaitJoyButton (void)
782 {
783 #if 0
784         int             oldbuttons, buttons;
785
786         oldbuttons = 0;
787         do
788         {
789                 I_WaitVBL (1);
790                 buttons =  ((inp(0x201) >> 4)&1)^1;
791                 if (buttons != oldbuttons)
792                 {
793                         oldbuttons = buttons;
794                         continue;
795                 }
796
797                 if ( (lastpress& 0x7f) == 1 )
798                 {
799                         joystickpresent = false;
800                         return false;
801                 }
802         } while ( !buttons);
803
804         do
805         {
806                 I_WaitVBL (1);
807                 buttons =  ((inp(0x201) >> 4)&1)^1;
808                 if (buttons != oldbuttons)
809                 {
810                         oldbuttons = buttons;
811                         continue;
812                 }
813
814                 if ( (lastpress& 0x7f) == 1 )
815                 {
816                         joystickpresent = false;
817                         return false;
818                 }
819         } while ( buttons);
820
821 #endif
822         return true;
823 }
824
825
826
827 /*
828 ===============
829 =
830 = I_StartupJoystick
831 =
832 ===============
833 */
834
835 int             basejoyx, basejoyy;
836
837 void I_StartupJoystick (void)
838 {
839         int     centerx, centery;
840
841         joystickpresent = 0;
842         if ( M_CheckParm ("-nojoy") || !usejoystick )
843                 return;
844
845         if (!I_ReadJoystick ())
846         {
847                 joystickpresent = false;
848                 tprintf ("joystick not found\n ",1);
849                 return;
850         }
851         tprintf ("joystick found\n",1);
852         joystickpresent = true;
853
854         tprintf ("CENTER the joystick and press button 1:",1);
855         if (!WaitJoyButton ())
856                 return;
857         I_ReadJoystick ();
858         centerx = joystickx;
859         centery = joysticky;
860
861         tprintf("\nPush the joystick to the UPPER LEFT corner and press button 1:",1);
862         if (!WaitJoyButton ())
863                 return;
864         I_ReadJoystick ();
865         joyxl = (centerx + joystickx)/2;
866         joyyl = (centerx + joysticky)/2;
867
868         tprintf("\nPush the joystick to the LOWER RIGHT corner and press button 1:",1);
869         if (!WaitJoyButton ())
870                 return;
871         I_ReadJoystick ();
872         joyxh = (centerx + joystickx)/2;
873         joyyh = (centery + joysticky)/2;
874         tprintf ("\n", 1);
875 }
876
877 /*
878 ===============
879 =
880 = I_JoystickEvents
881 =
882 ===============
883 */
884
885 void I_JoystickEvents (void)
886 {
887         event_t ev;
888
889 //
890 // joystick events
891 //
892         if (!joystickpresent)
893                 return;
894
895         I_ReadJoystick();
896         ev.type = ev_joystick;
897         ev.data1 =  0;  //((inp(0x201) >> 4)&15)^15;
898
899         if (joystickx < joyxl)
900                 ev.data2 = -1;
901         else if (joystickx > joyxh)
902                 ev.data2 = 1;
903         else
904                 ev.data2 = 0;
905         if (joysticky < joyyl)
906                 ev.data3 = -1;
907         else if (joysticky > joyyh)
908                 ev.data3 = 1;
909         else
910                 ev.data3 = 0;
911
912         D_PostEvent (&ev);
913 }
914
915
916 /*
917    ===============
918    =
919    = I_StartFrame
920    =
921    ===============
922    */
923  
924 void I_StartFrame (void)
925 {
926     I_JoystickEvents();
927 }
928
929
930 /*
931 ============================================================================
932
933                                         DPMI STUFF
934
935 ============================================================================
936 */
937
938 void I_DivException (void);
939 int I_SetDivException (void);
940
941
942
943 /*
944 ============================================================================
945
946                                         TIMER INTERRUPT
947
948 ============================================================================
949 */
950
951
952 /*
953 ===============
954 =
955 = I_Init
956 =
957 = hook interrupts and set graphics mode
958 =
959 ===============
960 */
961
962 void I_Init (void)
963 {
964         void I_StartupTimer(void);
965
966         novideo = M_CheckParm("novideo");
967         I_StartupMouse();
968 //      tprintf("I_StartupJoystick ",1);
969 //      I_StartupJoystick();
970         tprintf("S_Init... ",1);
971         S_Init();
972         S_Start();
973
974     I_StartupTimer();
975 }
976
977
978 /*
979 ===============
980 =
981 = I_Shutdown
982 =
983 = return to default system state
984 =
985 ===============
986 */
987
988 void I_ShutdownNet (void)
989 {
990         free (doomcom);
991 }
992
993 void I_Shutdown (void)
994 {
995         I_ShutdownGraphics ();
996         I_ShutdownNet ();
997         S_ShutDown ();
998 }
999
1000
1001 /*
1002 ================
1003 =
1004 = I_Error
1005 =
1006 ================
1007 */
1008
1009 void I_Error (char *error, ...)
1010 {
1011         va_list argptr;
1012
1013         D_QuitNetGame ();
1014         I_Shutdown ();
1015         va_start (argptr,error);
1016         vprintf (error, argptr);
1017         va_end (argptr);
1018         printf ("\n");
1019         exit (1);
1020 }
1021
1022 //--------------------------------------------------------------------------
1023 //
1024 // I_Quit
1025 //
1026 // Shuts down net game, saves defaults, prints the exit text message,
1027 // goes to text mode, and exits.
1028 //
1029 //--------------------------------------------------------------------------
1030
1031 void put_dos2ansi (byte attrib)
1032 {
1033         byte fore,back,blink=0,intens=0;
1034         int table[] = {30,34,32,36,31,35,33,37};
1035         
1036         fore = attrib&15;       // bits 0-3
1037         back = attrib&112; // bits 4-6
1038         blink = attrib&128; // bit 7
1039         
1040         // Fix background, blink is either on or off.
1041         back = back>>4;
1042
1043         // Fix foreground
1044         if (fore > 7) {
1045                 intens = 1;
1046                 fore-=8;
1047         }
1048
1049         // Convert fore/back
1050         fore = table[fore];
1051         back = table[back] + 10;
1052
1053         // 'Render'
1054         if (blink)
1055                 printf ("\033[%d;5;%dm\033[%dm", intens, fore, back);
1056         else
1057                 printf ("\033[%d;25;%dm\033[%dm", intens, fore, back);
1058 }
1059
1060 void I_Quit(void)
1061 {
1062         int i;
1063         byte *scr;
1064         
1065         D_QuitNetGame();
1066         M_SaveDefaults();
1067         I_Shutdown();
1068
1069         scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
1070 /*
1071         memcpy((void *)0xb8000, scr, 80*25*2);
1072         regs.w.ax = 0x0200;
1073         regs.h.bh = 0;
1074         regs.h.dl = 0;
1075         regs.h.dh = 23;
1076         int386(0x10, (const union REGS *)&regs, &regs); // Set text pos
1077         _settextposition(24, 1);
1078 */
1079         for (i=0; i< 80*25*2; i+=2) {
1080                 put_dos2ansi(scr[i+1]);
1081                 putchar (scr[i]);
1082         }
1083         // Cleanup after all that ANSI stuff
1084         printf ("\033[m");
1085         W_Shutdown ();
1086         Z_Shutdown ();
1087         exit(0);
1088 }
1089
1090 /*
1091 ===============
1092 =
1093 = I_ZoneBase
1094 =
1095 ===============
1096 */
1097
1098 byte *I_ZoneBase (int *size)
1099 {
1100         byte *ptr;
1101         int heap = 0x800000;
1102
1103         ptr = malloc ( heap );
1104
1105         if ( ! ptr )
1106                 I_Error ("  Insufficient DPMI memory!");
1107
1108         *size = heap;
1109         return ptr;
1110 }
1111
1112 /*
1113 =============
1114 =
1115 = I_AllocLow
1116 =
1117 =============
1118 */
1119
1120 byte *I_AllocLow (int length)
1121 {
1122         return malloc( length );
1123 }
1124
1125 /*
1126 ============================================================================
1127
1128                                                 NETWORKING
1129
1130 ============================================================================
1131 */
1132
1133 /* // FUCKED LINES
1134 typedef struct
1135 {
1136         char    priv[508];
1137 } doomdata_t;
1138 */ // FUCKED LINES
1139
1140 #define DOOMCOM_ID              0x12345678l
1141
1142 /* // FUCKED LINES
1143 typedef struct
1144 {
1145         long    id;
1146         short   intnum;                 // DOOM executes an int to execute commands
1147
1148 // communication between DOOM and the driver
1149         short   command;                // CMD_SEND or CMD_GET
1150         short   remotenode;             // dest for send, set by get (-1 = no packet)
1151         short   datalength;             // bytes in doomdata to be sent
1152
1153 // info common to all nodes
1154         short   numnodes;               // console is allways node 0
1155         short   ticdup;                 // 1 = no duplication, 2-5 = dup for slow nets
1156         short   extratics;              // 1 = send a backup tic in every packet
1157         short   deathmatch;             // 1 = deathmatch
1158         short   savegame;               // -1 = new game, 0-5 = load savegame
1159         short   episode;                // 1-3
1160         short   map;                    // 1-9
1161         short   skill;                  // 1-5
1162
1163 // info specific to this node
1164         short   consoleplayer;
1165         short   numplayers;
1166         short   angleoffset;    // 1 = left, 0 = center, -1 = right
1167         short   drone;                  // 1 = drone
1168
1169 // packet data to be sent
1170         doomdata_t      data;
1171 } doomcom_t;
1172 */ // FUCKED LINES
1173
1174 extern  doomcom_t               *doomcom;
1175
1176 /*
1177 ====================
1178 =
1179 = I_InitNetwork
1180 =
1181 ====================
1182 */
1183
1184 void I_InitNetwork (void)
1185 {
1186         int             i;
1187
1188         i = M_CheckParm ("-net");
1189         if (!i)
1190         {
1191         //
1192         // single player game
1193         //
1194                 doomcom = malloc (sizeof (*doomcom) );
1195                 memset (doomcom, 0, sizeof(*doomcom) );
1196                 netgame = false;
1197                 doomcom->id = DOOMCOM_ID;
1198                 doomcom->numplayers = doomcom->numnodes = 1;
1199                 doomcom->deathmatch = false;
1200                 doomcom->consoleplayer = 0;
1201                 doomcom->ticdup = 1;
1202                 doomcom->extratics = 0;
1203                 return;
1204         }
1205         netgame = true;
1206         doomcom = (doomcom_t *)atoi(myargv[i+1]);
1207 //DEBUG
1208 doomcom->skill = startskill;
1209 doomcom->episode = startepisode;
1210 doomcom->map = startmap;
1211 doomcom->deathmatch = deathmatch;
1212 }
1213
1214 void I_NetCmd (void)
1215 {
1216         if (!netgame)
1217                 I_Error ("I_NetCmd when not in netgame");
1218 }
1219
1220 //=========================================================================
1221 //
1222 // I_CheckExternDriver
1223 //
1224 //              Checks to see if a vector, and an address for an external driver
1225 //                      have been passed.
1226 //=========================================================================
1227
1228 void I_CheckExternDriver(void)
1229 {
1230         int i;
1231
1232         if(!(i = M_CheckParm("-externdriver")))
1233         {
1234                 return;
1235         }
1236         i_ExternData = (externdata_t *)atoi(myargv[i+1]);
1237         i_Vector = i_ExternData->vector;
1238
1239         useexterndriver = true;
1240 }
1241
1242
1243 int main( int argc, char** argv )
1244 {
1245         myargc = argc;
1246         myargv = argv;
1247         D_DoomMain();
1248         return 0;
1249 }
1250
1251 fixed_t FixedMul (fixed_t a, fixed_t b)
1252 {
1253     return ((long long) a * (long long) b) >> 16;
1254 }
1255
1256 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
1257 {
1258     double c;
1259
1260     c = ((double)a) / ((double)b) * FRACUNIT;
1261
1262     if (c >= 2147483648.0 || c < -2147483648.0)
1263         I_Error("FixedDiv: divide by zero");
1264     return (fixed_t) c;
1265 }
1266
1267 //EOF