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