]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/i_ibm.c
More 64bit fixes
[theoddone33/hheretic.git] / base / i_ibm.c
1
2 // I_IBM.C
3
4 #include <dos.h>
5 #include <conio.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include <graph.h>
9 #include "doomdef.h"
10 #include "r_local.h"
11 #include "sounds.h"
12 #include "i_sound.h"
13 #include "dmx.h"
14
15 // Macros
16
17 #define DPMI_INT 0x31
18 //#define NOKBD
19 //#define NOTIMER
20
21 // Public Data
22
23 int DisplayTicker = 0;
24
25 // Code
26
27 void main(int argc, char **argv)
28 {
29         myargc = argc;
30         myargv = argv;
31         D_DoomMain();
32 }
33
34 void I_StartupNet (void);
35 void I_ShutdownNet (void);
36 void I_ReadExternDriver(void);
37
38 typedef struct
39 {
40         unsigned        edi, esi, ebp, reserved, ebx, edx, ecx, eax;
41         unsigned short  flags, es, ds, fs, gs, ip, cs, sp, ss;
42 } dpmiregs_t;
43
44 extern  dpmiregs_t      dpmiregs;
45
46 void I_ReadMouse (void);
47 void I_InitDiskFlash (void);
48
49 extern  int     usemouse, usejoystick;
50
51 extern void **lumpcache;
52
53 /*
54 ===============================================================================
55
56                 MUSIC & SFX API
57
58 ===============================================================================
59 */
60
61 static channel_t channel[MAX_CHANNELS];
62
63 static int rs; //the current registered song.
64 int mus_song = -1;
65 int mus_lumpnum;
66 void *mus_sndptr;
67 byte *soundCurve;
68
69 extern sfxinfo_t S_sfx[];
70 extern musicinfo_t S_music[];
71
72 extern int snd_DesiredMusicDevice;
73 extern int snd_DesiredSfxDevice;
74 extern int snd_MaxVolume;
75 extern int snd_MusicVolume;
76 extern int snd_Channels;
77
78 extern int startepisode;
79 extern int startmap;
80
81 int AmbChan;
82
83 void S_Start(void)
84 {
85         int i;
86
87         S_StartSong((gameepisode-1)*9 + gamemap-1, true);
88
89         //stop all sounds
90         for(i=0; i < snd_Channels; i++)
91         {
92                 if(channel[i].handle)
93                 {
94                         S_StopSound(channel[i].mo);
95                 }
96         }
97         memset(channel, 0, 8*sizeof(channel_t));
98 }
99
100 void S_StartSong(int song, boolean loop)
101 {
102         if(song == mus_song)
103         { // don't replay an old song
104                 return;
105         }
106         if(rs)
107         {
108                 I_StopSong(rs);
109                 I_UnRegisterSong(rs);
110                 Z_ChangeTag(lumpcache[mus_lumpnum], PU_CACHE);
111                 #ifdef __WATCOMC__
112                         _dpmi_unlockregion(mus_sndptr, lumpinfo[mus_lumpnum].size);
113                 #endif
114         }
115         if(song < mus_e1m1 || song > NUMMUSIC)
116         {
117                 return;
118         }
119         mus_lumpnum = W_GetNumForName(S_music[song].name);
120         mus_sndptr = W_CacheLumpNum(mus_lumpnum, PU_MUSIC);
121         #ifdef __WATCOMC__
122                 _dpmi_lockregion(mus_sndptr, lumpinfo[mus_lumpnum].size);
123         #endif
124         rs = I_RegisterSong(mus_sndptr);
125         I_PlaySong(rs, loop); //'true' denotes endless looping.
126         mus_song = song;
127 }
128
129 void S_StartSound(mobj_t *origin, int sound_id)
130 {
131         int dist, vol;
132         int i;
133         int sound;
134         int priority;
135         int sep;
136         int angle;
137         int absx;
138         int absy;
139
140         static int sndcount = 0;
141         int chan;
142
143         if(sound_id==0 || snd_MaxVolume == 0)
144                 return;
145         if(origin == NULL)
146         {
147                 origin = players[consoleplayer].mo;
148         }
149
150 // calculate the distance before other stuff so that we can throw out
151 // sounds that are beyond the hearing range.
152         absx = abs(origin->x-players[consoleplayer].mo->x);
153         absy = abs(origin->y-players[consoleplayer].mo->y);
154         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
155         dist >>= FRACBITS;
156 //  dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS;
157
158         if(dist >= MAX_SND_DIST)
159         {
160 //      dist = MAX_SND_DIST - 1;
161           return; //sound is beyond the hearing range...
162         }
163         if(dist < 0)
164         {
165                 dist = 0;
166         }
167         priority = S_sfx[sound_id].priority;
168         priority *= (10 - (dist/160));
169         if(!S_StopSoundID(sound_id, priority))
170         {
171                 return; // other sounds have greater priority
172         }
173         for(i=0; i<snd_Channels; i++)
174         {
175                 if(origin->player)
176                 {
177                         i = snd_Channels;
178                         break; // let the player have more than one sound.
179                 }
180                 if(origin == channel[i].mo)
181                 { // only allow other mobjs one sound
182                         S_StopSound(channel[i].mo);
183                         break;
184                 }
185         }
186         if(i >= snd_Channels)
187         {
188                 if(sound_id >= sfx_wind)
189                 {
190                         if(AmbChan != -1 && S_sfx[sound_id].priority <=
191                                 S_sfx[channel[AmbChan].sound_id].priority)
192                         {
193                                 return; //ambient channel already in use
194                         }
195                         else
196                         {
197                                 AmbChan = -1;
198                         }
199                 }
200                 for(i=0; i<snd_Channels; i++)
201                 {
202                         if(channel[i].mo == NULL)
203                         {
204                                 break;
205                         }
206                 }
207                 if(i >= snd_Channels)
208                 {
209                         //look for a lower priority sound to replace.
210                         sndcount++;
211                         if(sndcount >= snd_Channels)
212                         {
213                                 sndcount = 0;
214                         }
215                         for(chan=0; chan < snd_Channels; chan++)
216                         {
217                                 i = (sndcount+chan)%snd_Channels;
218                                 if(priority >= channel[i].priority)
219                                 {
220                                         chan = -1; //denote that sound should be replaced.
221                                         break;
222                                 }
223                         }
224                         if(chan != -1)
225                         {
226                                 return; //no free channels.
227                         }
228                         else //replace the lower priority sound.
229                         {
230                                 if(channel[i].handle)
231                                 {
232                                         if(I_SoundIsPlaying(channel[i].handle))
233                                         {
234                                                 I_StopSound(channel[i].handle);
235                                         }
236                                         if(S_sfx[channel[i].sound_id].usefulness > 0)
237                                         {
238                                                 S_sfx[channel[i].sound_id].usefulness--;
239                                         }
240
241                                         if(AmbChan == i)
242                                         {
243                                                 AmbChan = -1;
244                                         }
245                                 }
246                         }
247                 }
248         }
249         if(S_sfx[sound_id].lumpnum == 0)
250         {
251                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
252         }
253         if(S_sfx[sound_id].snd_ptr == NULL)
254         {
255                 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
256                         PU_SOUND);
257                 #ifdef __WATCOMC__
258                 _dpmi_lockregion(S_sfx[sound_id].snd_ptr,
259                         lumpinfo[S_sfx[sound_id].lumpnum].size);
260                 #endif
261         }
262
263         // calculate the volume based upon the distance from the sound origin.
264 //      vol = (snd_MaxVolume*16 + dist*(-snd_MaxVolume*16)/MAX_SND_DIST)>>9;
265         vol = soundCurve[dist];
266
267         if(origin == players[consoleplayer].mo)
268         {
269                 sep = 128;
270         }
271         else
272         {
273                 angle = R_PointToAngle2(players[consoleplayer].mo->x,
274                         players[consoleplayer].mo->y, channel[i].mo->x, channel[i].mo->y);
275                 angle = (angle-viewangle)>>24;
276                 sep = angle*2-128;
277                 if(sep < 64)
278                         sep = -sep;
279                 if(sep > 192)
280                         sep = 512-sep;
281         }
282
283         channel[i].pitch = (byte)(127+(M_Random()&7)-(M_Random()&7));
284         channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol, sep, channel[i].pitch, 0);
285         channel[i].mo = origin;
286         channel[i].sound_id = sound_id;
287         channel[i].priority = priority;
288         if(sound_id >= sfx_wind)
289         {
290                 AmbChan = i;
291         }
292         if(S_sfx[sound_id].usefulness == -1)
293         {
294                 S_sfx[sound_id].usefulness = 1;
295         }
296         else
297         {
298                 S_sfx[sound_id].usefulness++;
299         }
300 }
301
302 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
303 {
304         int dist;
305         int i;
306         int sep;
307
308         static int sndcount;
309         int chan;
310
311         if(sound_id == 0 || snd_MaxVolume == 0)
312                 return;
313         if(origin == NULL)
314         {
315                 origin = players[consoleplayer].mo;
316         }
317
318         if(volume == 0)
319         {
320                 return;
321         }
322         volume = (volume*(snd_MaxVolume+1)*8)>>7;
323
324 // no priority checking, as ambient sounds would be the LOWEST.
325         for(i=0; i<snd_Channels; i++)
326         {
327                 if(channel[i].mo == NULL)
328                 {
329                         break;
330                 }
331         }
332         if(i >= snd_Channels)
333         {
334                 return;
335         }
336         if(S_sfx[sound_id].lumpnum == 0)
337         {
338                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
339         }
340         if(S_sfx[sound_id].snd_ptr == NULL)
341         {
342                 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
343                         PU_SOUND);
344                 #ifdef __WATCOMC__
345                 _dpmi_lockregion(S_sfx[sound_id].snd_ptr,
346                         lumpinfo[S_sfx[sound_id].lumpnum].size);
347                 #endif
348         }
349         channel[i].pitch = (byte)(127-(M_Random()&3)+(M_Random()&3));
350         channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, volume, 128, channel[i].pitch, 0);
351         channel[i].mo = origin;
352         channel[i].sound_id = sound_id;
353         channel[i].priority = 1; //super low priority.
354         if(S_sfx[sound_id].usefulness == -1)
355         {
356                 S_sfx[sound_id].usefulness = 1;
357         }
358         else
359         {
360                 S_sfx[sound_id].usefulness++;
361         }
362 }
363
364 boolean S_StopSoundID(int sound_id, int priority)
365 {
366         int i;
367         int lp; //least priority
368         int found;
369
370         if(S_sfx[sound_id].numchannels == -1)
371         {
372                 return(true);
373         }
374         lp = -1; //denote the argument sound_id
375         found = 0;
376         for(i=0; i<snd_Channels; i++)
377         {
378                 if(channel[i].sound_id == sound_id && channel[i].mo)
379                 {
380                         found++; //found one.  Now, should we replace it??
381                         if(priority >= channel[i].priority)
382                         { // if we're gonna kill one, then this'll be it
383                                 lp = i;
384                                 priority = channel[i].priority;
385                         }
386                 }
387         }
388         if(found < S_sfx[sound_id].numchannels)
389         {
390                 return(true);
391         }
392         else if(lp == -1)
393         {
394                 return(false); // don't replace any sounds
395         }
396         if(channel[lp].handle)
397         {
398                 if(I_SoundIsPlaying(channel[lp].handle))
399                 {
400                         I_StopSound(channel[lp].handle);
401                 }
402                 if(S_sfx[channel[i].sound_id].usefulness > 0)
403                 {
404                         S_sfx[channel[i].sound_id].usefulness--;
405                 }
406                 channel[lp].mo = NULL;
407         }
408         return(true);
409 }
410
411 void S_StopSound(mobj_t *origin)
412 {
413         int i;
414
415         for(i=0;i<snd_Channels;i++)
416         {
417                 if(channel[i].mo == origin)
418                 {
419                         I_StopSound(channel[i].handle);
420                         if(S_sfx[channel[i].sound_id].usefulness > 0)
421                         {
422                                 S_sfx[channel[i].sound_id].usefulness--;
423                         }
424                         channel[i].handle = 0;
425                         channel[i].mo = NULL;
426                         if(AmbChan == i)
427                         {
428                                 AmbChan = -1;
429                         }
430                 }
431         }
432 }
433
434 void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
435 {
436         int i;
437
438         for(i=0;i<snd_Channels;i++)
439         {
440                 if(channel[i].mo == oldactor)
441                         channel[i].mo = newactor;
442         }
443 }
444
445 void S_PauseSound(void)
446 {
447         I_PauseSong(rs);
448 }
449
450 void S_ResumeSound(void)
451 {
452         I_ResumeSong(rs);
453 }
454
455 static int nextcleanup;
456
457 void S_UpdateSounds(mobj_t *listener)
458 {
459         int i, dist, vol;
460         int angle;
461         int sep;
462         int priority;
463         int absx;
464         int absy;
465
466         listener = players[consoleplayer].mo;
467         if(snd_MaxVolume == 0)
468         {
469                 return;
470         }
471         if(nextcleanup < gametic)
472         {
473                 for(i=0; i < NUMSFX; i++)
474                 {
475                         if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
476                         {
477                                 if(lumpcache[S_sfx[i].lumpnum])
478                                 {
479                                         if(((memblock_t *)((byte *)(lumpcache[S_sfx[i].lumpnum])-
480                                                 sizeof(memblock_t)))->id == 0x1d4a11)
481                                         { // taken directly from the Z_ChangeTag macro
482                                                 Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum], PU_CACHE);
483                                                 #ifdef __WATCOMC__
484                                                         _dpmi_unlockregion(S_sfx[i].snd_ptr, lumpinfo[S_sfx[i].lumpnum].size);
485                                                 #endif
486                                         }
487                                 }
488                                 S_sfx[i].usefulness = -1;
489                                 S_sfx[i].snd_ptr = NULL;
490                         }
491                 }
492                 nextcleanup = gametic+35; //CLEANUP DEBUG cleans every second
493         }
494         for(i=0;i<snd_Channels;i++)
495         {
496                 if(!channel[i].handle || S_sfx[channel[i].sound_id].usefulness == -1)
497                 {
498                         continue;
499                 }
500                 if(!I_SoundIsPlaying(channel[i].handle))
501                 {
502                         if(S_sfx[channel[i].sound_id].usefulness > 0)
503                         {
504                                 S_sfx[channel[i].sound_id].usefulness--;
505                         }
506                         channel[i].handle = 0;
507                         channel[i].mo = NULL;
508                         channel[i].sound_id = 0;
509                         if(AmbChan == i)
510                         {
511                                 AmbChan = -1;
512                         }
513                 }
514                 if(channel[i].mo == NULL || channel[i].sound_id == 0
515                         || channel[i].mo == players[consoleplayer].mo)
516                 {
517                         continue;
518                 }
519                 else
520                 {
521                         absx = abs(channel[i].mo->x-players[consoleplayer].mo->x);
522                         absy = abs(channel[i].mo->y-players[consoleplayer].mo->y);
523                         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
524                         dist >>= FRACBITS;
525 //          dist = P_AproxDistance(channel[i].mo->x-listener->x, channel[i].mo->y-listener->y)>>FRACBITS;
526
527                         if(dist >= MAX_SND_DIST)
528                         {
529                                 S_StopSound(channel[i].mo);
530                                 continue;
531                         }
532                         if(dist < 0)
533                                 dist = 0;
534
535 // calculate the volume based upon the distance from the sound origin.
536 //          vol = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+dist)*(snd_MaxVolume*8))>>7;
537                         vol = soundCurve[dist];
538
539                         angle = R_PointToAngle2(players[consoleplayer].mo->x,
540                                 players[consoleplayer].mo->y, channel[i].mo->x, channel[i].mo->y);
541                         angle = (angle-viewangle)>>24;
542                         sep = angle*2-128;
543                         if(sep < 64)
544                                 sep = -sep;
545                         if(sep > 192)
546                                 sep = 512-sep;
547                         I_UpdateSoundParams(channel[i].handle, vol, sep, channel[i].pitch);
548                         priority = S_sfx[channel[i].sound_id].priority;
549                         priority *= (10 - (dist>>8));
550                         channel[i].priority = priority;
551                 }
552         }
553 }
554
555 void S_Init(void)
556 {
557         soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
558         I_StartupSound();
559         if(snd_Channels > 8)
560         {
561                 snd_Channels = 8;
562         }
563         I_SetChannels(snd_Channels);
564         I_SetMusicVolume(snd_MusicVolume);
565         S_SetMaxVolume(true);
566 }
567
568 void S_GetChannelInfo(SoundInfo_t *s)
569 {
570         int i;
571         ChanInfo_t *c;
572
573         s->channelCount = snd_Channels;
574         s->musicVolume = snd_MusicVolume;
575         s->soundVolume = snd_MaxVolume;
576         for(i = 0; i < snd_Channels; i++)
577         {
578                 c = &s->chan[i];
579                 c->id = channel[i].sound_id;
580                 c->priority = channel[i].priority;
581                 c->name = S_sfx[c->id].name;
582                 c->mo = channel[i].mo;
583                 c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)
584                         >>FRACBITS;
585         }
586 }
587
588 void S_SetMaxVolume(boolean fullprocess)
589 {
590         int i;
591
592         if(!fullprocess)
593         {
594                 soundCurve[0] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE))*(snd_MaxVolume*8))>>7;
595         }
596         else
597         {
598                 for(i = 0; i < MAX_SND_DIST; i++)
599                 {
600                         soundCurve[i] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+i)*(snd_MaxVolume*8))>>7;
601                 }
602         }
603 }
604
605 static boolean musicPaused;
606 void S_SetMusicVolume(void)
607 {
608         I_SetMusicVolume(snd_MusicVolume);
609         if(snd_MusicVolume == 0)
610         {
611                 I_PauseSong(rs);
612                 musicPaused = true;
613         }
614         else if(musicPaused)
615         {
616                 musicPaused = false;
617                 I_ResumeSong(rs);
618         }
619 }
620
621 void S_ShutDown(void)
622 {
623         extern int tsm_ID;
624         if(tsm_ID != -1)
625         {
626                 I_StopSong(rs);
627                 I_UnRegisterSong(rs);
628                 I_ShutdownSound();
629         }
630 }
631
632 /*
633 =============================================================================
634
635                                                         CONSTANTS
636
637 =============================================================================
638 */
639
640 #define SC_INDEX                0x3C4
641 #define SC_RESET                0
642 #define SC_CLOCK                1
643 #define SC_MAPMASK              2
644 #define SC_CHARMAP              3
645 #define SC_MEMMODE              4
646
647 #define CRTC_INDEX              0x3D4
648 #define CRTC_H_TOTAL    0
649 #define CRTC_H_DISPEND  1
650 #define CRTC_H_BLANK    2
651 #define CRTC_H_ENDBLANK 3
652 #define CRTC_H_RETRACE  4
653 #define CRTC_H_ENDRETRACE 5
654 #define CRTC_V_TOTAL    6
655 #define CRTC_OVERFLOW   7
656 #define CRTC_ROWSCAN    8
657 #define CRTC_MAXSCANLINE 9
658 #define CRTC_CURSORSTART 10
659 #define CRTC_CURSOREND  11
660 #define CRTC_STARTHIGH  12
661 #define CRTC_STARTLOW   13
662 #define CRTC_CURSORHIGH 14
663 #define CRTC_CURSORLOW  15
664 #define CRTC_V_RETRACE  16
665 #define CRTC_V_ENDRETRACE 17
666 #define CRTC_V_DISPEND  18
667 #define CRTC_OFFSET             19
668 #define CRTC_UNDERLINE  20
669 #define CRTC_V_BLANK    21
670 #define CRTC_V_ENDBLANK 22
671 #define CRTC_MODE               23
672 #define CRTC_LINECOMPARE 24
673
674
675 #define GC_INDEX                0x3CE
676 #define GC_SETRESET             0
677 #define GC_ENABLESETRESET 1
678 #define GC_COLORCOMPARE 2
679 #define GC_DATAROTATE   3
680 #define GC_READMAP              4
681 #define GC_MODE                 5
682 #define GC_MISCELLANEOUS 6
683 #define GC_COLORDONTCARE 7
684 #define GC_BITMASK              8
685
686 #define ATR_INDEX               0x3c0
687 #define ATR_MODE                16
688 #define ATR_OVERSCAN    17
689 #define ATR_COLORPLANEENABLE 18
690 #define ATR_PELPAN              19
691 #define ATR_COLORSELECT 20
692
693 #define STATUS_REGISTER_1    0x3da
694
695 #define PEL_WRITE_ADR   0x3c8
696 #define PEL_READ_ADR    0x3c7
697 #define PEL_DATA                0x3c9
698 #define PEL_MASK                0x3c6
699
700 boolean grmode;
701
702 //==================================================
703 //
704 // joystick vars
705 //
706 //==================================================
707
708 boolean         joystickpresent;
709 extern  unsigned        joystickx, joysticky;
710 boolean I_ReadJoystick (void);          // returns false if not connected
711
712
713 //==================================================
714
715 #define VBLCOUNTER              34000           // hardware tics to a frame
716
717
718 #define TIMERINT 8
719 #define KEYBOARDINT 9
720
721 #define CRTCOFF (_inbyte(STATUS_REGISTER_1)&1)
722 #define CLI     _disable()
723 #define STI     _enable()
724
725 #define _outbyte(x,y) (outp(x,y))
726 #define _outhword(x,y) (outpw(x,y))
727
728 #define _inbyte(x) (inp(x))
729 #define _inhword(x) (inpw(x))
730
731 #define MOUSEB1 1
732 #define MOUSEB2 2
733 #define MOUSEB3 4
734
735 boolean mousepresent;
736 //static  int tsm_ID = -1; // tsm init flag
737
738 //===============================
739
740 int             ticcount;
741
742 // REGS stuff used for int calls
743 union REGS regs;
744 struct SREGS segregs;
745
746 boolean novideo; // if true, stay in text mode for debugging
747
748 #define KBDQUESIZE 32
749 byte keyboardque[KBDQUESIZE];
750 int kbdtail, kbdhead;
751
752 #define KEY_LSHIFT      0xfe
753
754 #define KEY_INS         (0x80+0x52)
755 #define KEY_DEL         (0x80+0x53)
756 #define KEY_PGUP        (0x80+0x49)
757 #define KEY_PGDN        (0x80+0x51)
758 #define KEY_HOME        (0x80+0x47)
759 #define KEY_END         (0x80+0x4f)
760
761 #define SC_RSHIFT       0x36
762 #define SC_LSHIFT       0x2a
763
764 byte        scantokey[128] =
765                                         {
766 //  0           1       2       3       4       5       6       7
767 //  8           9       A       B       C       D       E       F
768         0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
769         '7',    '8',    '9',    '0',    '-',    '=',    KEY_BACKSPACE, 9, // 0
770         'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
771         'o',    'p',    '[',    ']',    13 ,    KEY_RCTRL,'a',  's',      // 1
772         'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
773         39 ,    '`',    KEY_LSHIFT,92,  'z',    'x',    'c',    'v',      // 2
774         'b',    'n',    'm',    ',',    '.',    '/',    KEY_RSHIFT,'*',
775         KEY_RALT,' ',   0  ,    KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,   // 3
776         KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,0  ,    0  , KEY_HOME,
777         KEY_UPARROW,KEY_PGUP,'-',KEY_LEFTARROW,'5',KEY_RIGHTARROW,'+',KEY_END, //4
778         KEY_DOWNARROW,KEY_PGDN,KEY_INS,KEY_DEL,0,0,             0,              KEY_F11,
779         KEY_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
780         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
781         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
782         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
783         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
784                                         };
785
786 //==========================================================================
787
788 //--------------------------------------------------------------------------
789 //
790 // FUNC I_GetTime
791 //
792 // Returns time in 1/35th second tics.
793 //
794 //--------------------------------------------------------------------------
795
796 int I_GetTime (void)
797 {
798 #ifdef NOTIMER
799         ticcount++;
800 #endif
801         return(ticcount);
802 }
803
804 //--------------------------------------------------------------------------
805 //
806 // PROC I_ColorBorder
807 //
808 //--------------------------------------------------------------------------
809
810 void I_ColorBorder(void)
811 {
812         int i;
813
814         I_WaitVBL(1);
815         _outbyte(PEL_WRITE_ADR, 0);
816         for(i = 0; i < 3; i++)
817         {
818                 _outbyte(PEL_DATA, 63);
819         }
820 }
821
822 //--------------------------------------------------------------------------
823 //
824 // PROC I_UnColorBorder
825 //
826 //--------------------------------------------------------------------------
827
828 void I_UnColorBorder(void)
829 {
830         int i;
831
832         I_WaitVBL(1);
833         _outbyte(PEL_WRITE_ADR, 0);
834         for(i = 0; i < 3; i++)
835         {
836                 _outbyte(PEL_DATA, 0);
837         }
838 }
839
840 /*
841 ============================================================================
842
843                                                                 USER INPUT
844
845 ============================================================================
846 */
847
848 //--------------------------------------------------------------------------
849 //
850 // PROC I_WaitVBL
851 //
852 //--------------------------------------------------------------------------
853
854 void I_WaitVBL(int vbls)
855 {
856         int i;
857         int old;
858         int stat;
859
860         if(novideo)
861         {
862                 return;
863         }
864         while(vbls--)
865         {
866                 do
867                 {
868                         stat = inp(STATUS_REGISTER_1);
869                         if(stat&8)
870                         {
871                                 break;
872                         }
873                 } while(1);
874                 do
875                 {
876                         stat = inp(STATUS_REGISTER_1);
877                         if((stat&8) == 0)
878                         {
879                                 break;
880                         }
881                 } while(1);
882         }
883 }
884
885 //--------------------------------------------------------------------------
886 //
887 // PROC I_SetPalette
888 //
889 // Palette source must use 8 bit RGB elements.
890 //
891 //--------------------------------------------------------------------------
892
893 void I_SetPalette(byte *palette)
894 {
895         int i;
896
897         if(novideo)
898         {
899                 return;
900         }
901         I_WaitVBL(1);
902         _outbyte(PEL_WRITE_ADR, 0);
903         for(i = 0; i < 768; i++)
904         {
905                 _outbyte(PEL_DATA, (gammatable[usegamma][*palette++])>>2);
906         }
907 }
908
909 /*
910 ============================================================================
911
912                                                         GRAPHICS MODE
913
914 ============================================================================
915 */
916
917 byte *pcscreen, *destscreen, *destview;
918
919
920 /*
921 ==============
922 =
923 = I_Update
924 =
925 ==============
926 */
927
928 int UpdateState;
929 extern int screenblocks;
930
931 void I_Update (void)
932 {
933         int i;
934         byte *dest;
935         int tics;
936         static int lasttic;
937
938 //
939 // blit screen to video
940 //
941         if(DisplayTicker)
942         {
943                 if(screenblocks > 9 || UpdateState&(I_FULLSCRN|I_MESSAGES))
944                 {
945                         dest = (byte *)screen;
946                 }
947                 else
948                 {
949                         dest = (byte *)pcscreen;
950                 }
951                 tics = ticcount-lasttic;
952                 lasttic = ticcount;
953                 if(tics > 20)
954                 {
955                         tics = 20;
956                 }
957                 for(i = 0; i < tics; i++)
958                 {
959                         *dest = 0xff;
960                         dest += 2;
961                 }
962                 for(i = tics; i < 20; i++)
963                 {
964                         *dest = 0x00;
965                         dest += 2;
966                 }
967         }
968         if(UpdateState == I_NOUPDATE)
969         {
970                 return;
971         }
972         if(UpdateState&I_FULLSCRN)
973         {
974                 memcpy(pcscreen, screen, SCREENWIDTH*SCREENHEIGHT);
975                 UpdateState = I_NOUPDATE; // clear out all draw types
976         }
977         if(UpdateState&I_FULLVIEW)
978         {
979                 if(UpdateState&I_MESSAGES && screenblocks > 7)
980                 {
981                         for(i = 0; i <
982                                 (viewwindowy+viewheight)*SCREENWIDTH; i += SCREENWIDTH)
983                         {
984                                 memcpy(pcscreen+i, screen+i, SCREENWIDTH);
985                         }
986                         UpdateState &= ~(I_FULLVIEW|I_MESSAGES);
987                 }
988                 else
989                 {
990                         for(i = viewwindowy*SCREENWIDTH+viewwindowx; i <
991                                 (viewwindowy+viewheight)*SCREENWIDTH; i += SCREENWIDTH)
992                         {
993                                 memcpy(pcscreen+i, screen+i, viewwidth);
994                         }
995                         UpdateState &= ~I_FULLVIEW;
996                 }
997         }
998         if(UpdateState&I_STATBAR)
999         {
1000                 memcpy(pcscreen+SCREENWIDTH*(SCREENHEIGHT-SBARHEIGHT),
1001                         screen+SCREENWIDTH*(SCREENHEIGHT-SBARHEIGHT),
1002                         SCREENWIDTH*SBARHEIGHT);
1003                 UpdateState &= ~I_STATBAR;
1004         }
1005         if(UpdateState&I_MESSAGES)
1006         {
1007                 memcpy(pcscreen, screen, SCREENWIDTH*28);
1008                 UpdateState &= ~I_MESSAGES;
1009         }
1010
1011 //  memcpy(pcscreen, screen, SCREENHEIGHT*SCREENWIDTH);
1012 }
1013
1014 //--------------------------------------------------------------------------
1015 //
1016 // PROC I_InitGraphics
1017 //
1018 //--------------------------------------------------------------------------
1019
1020 void I_InitGraphics(void)
1021 {
1022         if(novideo)
1023         {
1024                 return;
1025         }
1026         grmode = true;
1027         regs.w.ax = 0x13;
1028         int386(0x10, (const union REGS *)&regs, &regs);
1029         pcscreen = destscreen = (byte *)0xa0000;
1030         I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
1031         I_InitDiskFlash();
1032 }
1033
1034 //--------------------------------------------------------------------------
1035 //
1036 // PROC I_ShutdownGraphics
1037 //
1038 //--------------------------------------------------------------------------
1039
1040 void I_ShutdownGraphics(void)
1041 {
1042
1043         if(*(byte *)0x449 == 0x13) // don't reset mode if it didn't get set
1044         {
1045                 regs.w.ax = 3;
1046                 int386(0x10, &regs, &regs); // back to text mode
1047         }
1048 }
1049
1050 //--------------------------------------------------------------------------
1051 //
1052 // PROC I_ReadScreen
1053 //
1054 // Reads the screen currently displayed into a linear buffer.
1055 //
1056 //--------------------------------------------------------------------------
1057
1058 void I_ReadScreen(byte *scr)
1059 {
1060         memcpy(scr, screen, SCREENWIDTH*SCREENHEIGHT);
1061 }
1062
1063
1064 //===========================================================================
1065
1066 /*
1067 ===================
1068 =
1069 = I_StartTic
1070 =
1071 // called by D_DoomLoop
1072 // called before processing each tic in a frame
1073 // can call D_PostEvent
1074 // asyncronous interrupt functions should maintain private ques that are
1075 // read by the syncronous functions to be converted into events
1076 ===================
1077 */
1078
1079 /*
1080  OLD STARTTIC STUFF
1081
1082 void   I_StartTic (void)
1083 {
1084         int             k;
1085         event_t ev;
1086
1087
1088         I_ReadMouse ();
1089
1090 //
1091 // keyboard events
1092 //
1093         while (kbdtail < kbdhead)
1094         {
1095                 k = keyboardque[kbdtail&(KBDQUESIZE-1)];
1096
1097 //      if (k==14)
1098 //              I_Error ("exited");
1099
1100                 kbdtail++;
1101
1102                 // extended keyboard shift key bullshit
1103                 if ( (k&0x7f)==KEY_RSHIFT )
1104                 {
1105                         if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
1106                                 continue;
1107                         k &= 0x80;
1108                         k |= KEY_RSHIFT;
1109                 }
1110
1111                 if (k==0xe0)
1112                         continue;               // special / pause keys
1113                 if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
1114                         continue;                               // pause key bullshit
1115
1116                 if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
1117                 {
1118                         ev.type = ev_keydown;
1119                         ev.data1 = KEY_PAUSE;
1120                         D_PostEvent (&ev);
1121                         continue;
1122                 }
1123
1124                 if (k&0x80)
1125                         ev.type = ev_keyup;
1126                 else
1127                         ev.type = ev_keydown;
1128                 k &= 0x7f;
1129
1130                 ev.data1 = k;
1131                 //ev.data1 = scantokey[k];
1132
1133                 D_PostEvent (&ev);
1134         }
1135 }
1136 */
1137
1138 #define SC_UPARROW              0x48
1139 #define SC_DOWNARROW    0x50
1140 #define SC_LEFTARROW            0x4b
1141 #define SC_RIGHTARROW   0x4d
1142
1143 void   I_StartTic (void)
1144 {
1145         int             k;
1146         event_t ev;
1147
1148
1149         I_ReadMouse ();
1150
1151 //
1152 // keyboard events
1153 //
1154         while (kbdtail < kbdhead)
1155         {
1156                 k = keyboardque[kbdtail&(KBDQUESIZE-1)];
1157                 kbdtail++;
1158
1159                 // extended keyboard shift key bullshit
1160                 if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT )
1161                 {
1162                         if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
1163                                 continue;
1164                         k &= 0x80;
1165                         k |= SC_RSHIFT;
1166                 }
1167
1168                 if (k==0xe0)
1169                         continue;               // special / pause keys
1170                 if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
1171                         continue;                               // pause key bullshit
1172
1173                 if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
1174                 {
1175                         ev.type = ev_keydown;
1176                         ev.data1 = KEY_PAUSE;
1177                         D_PostEvent (&ev);
1178                         continue;
1179                 }
1180
1181                 if (k&0x80)
1182                         ev.type = ev_keyup;
1183                 else
1184                         ev.type = ev_keydown;
1185                 k &= 0x7f;
1186                 switch (k)
1187                 {
1188                 case SC_UPARROW:
1189                         ev.data1 = KEY_UPARROW;
1190                         break;
1191                 case SC_DOWNARROW:
1192                         ev.data1 = KEY_DOWNARROW;
1193                         break;
1194                 case SC_LEFTARROW:
1195                         ev.data1 = KEY_LEFTARROW;
1196                         break;
1197                 case SC_RIGHTARROW:
1198                         ev.data1 = KEY_RIGHTARROW;
1199                         break;
1200                 default:
1201                         ev.data1 = scantokey[k];
1202                         break;
1203                 }
1204                 D_PostEvent (&ev);
1205         }
1206
1207 }
1208
1209
1210 void   I_ReadKeys (void)
1211 {
1212         int             k;
1213         event_t ev;
1214
1215
1216         while (1)
1217         {
1218            while (kbdtail < kbdhead)
1219            {
1220                    k = keyboardque[kbdtail&(KBDQUESIZE-1)];
1221                    kbdtail++;
1222                    printf ("0x%x\n",k);
1223                    if (k == 1)
1224                            I_Quit ();
1225            }
1226         }
1227 }
1228
1229 /*
1230 ===============
1231 =
1232 = I_StartFrame
1233 =
1234 ===============
1235 */
1236
1237 void I_StartFrame (void)
1238 {
1239         I_JoystickEvents ();
1240         I_ReadExternDriver();
1241 }
1242
1243 /*
1244 ============================================================================
1245
1246                                         TIMER INTERRUPT
1247
1248 ============================================================================
1249 */
1250
1251 void I_ColorBlack (int r, int g, int b)
1252 {
1253 _outbyte (PEL_WRITE_ADR,0);
1254 _outbyte(PEL_DATA,r);
1255 _outbyte(PEL_DATA,g);
1256 _outbyte(PEL_DATA,b);
1257 }
1258
1259
1260 /*
1261 ================
1262 =
1263 = I_TimerISR
1264 =
1265 ================
1266 */
1267
1268 int I_TimerISR (void)
1269 {
1270         ticcount++;
1271         return 0;
1272 }
1273
1274 /*
1275 ============================================================================
1276
1277                                                 KEYBOARD
1278
1279 ============================================================================
1280 */
1281
1282 void (__interrupt __far *oldkeyboardisr) () = NULL;
1283
1284 int lastpress;
1285
1286 /*
1287 ================
1288 =
1289 = I_KeyboardISR
1290 =
1291 ================
1292 */
1293
1294 void __interrupt I_KeyboardISR (void)
1295 {
1296 // Get the scan code
1297
1298         keyboardque[kbdhead&(KBDQUESIZE-1)] = lastpress = _inbyte(0x60);
1299         kbdhead++;
1300
1301 // acknowledge the interrupt
1302
1303         _outbyte(0x20,0x20);
1304 }
1305
1306
1307
1308 /*
1309 ===============
1310 =
1311 = I_StartupKeyboard
1312 =
1313 ===============
1314 */
1315
1316 void I_StartupKeyboard (void)
1317 {
1318 #ifndef NOKBD
1319         oldkeyboardisr = _dos_getvect(KEYBOARDINT);
1320         _dos_setvect (0x8000 | KEYBOARDINT, I_KeyboardISR);
1321 #endif
1322
1323 //I_ReadKeys ();
1324 }
1325
1326
1327 void I_ShutdownKeyboard (void)
1328 {
1329         if (oldkeyboardisr)
1330                 _dos_setvect (KEYBOARDINT, oldkeyboardisr);
1331         *(short *)0x41c = *(short *)0x41a;      // clear bios key buffer
1332 }
1333
1334
1335
1336 /*
1337 ============================================================================
1338
1339                                                         MOUSE
1340
1341 ============================================================================
1342 */
1343
1344
1345 int I_ResetMouse (void)
1346 {
1347         regs.w.ax = 0;                  // reset
1348         int386 (0x33, &regs, &regs);
1349         return regs.w.ax;
1350 }
1351
1352
1353
1354 /*
1355 ================
1356 =
1357 = StartupMouse
1358 =
1359 ================
1360 */
1361
1362 void I_StartupCyberMan(void);
1363
1364 void I_StartupMouse (void)
1365 {
1366    int  (far *function)();
1367
1368    //
1369    // General mouse detection
1370    //
1371         mousepresent = 0;
1372         if ( M_CheckParm ("-nomouse") || !usemouse )
1373                 return;
1374
1375         if (I_ResetMouse () != 0xffff)
1376         {
1377                 tprintf ("Mouse: not present ",0);
1378                 return;
1379         }
1380         tprintf ("Mouse: detected ",0);
1381
1382         mousepresent = 1;
1383
1384         I_StartupCyberMan();
1385 }
1386
1387
1388 /*
1389 ================
1390 =
1391 = ShutdownMouse
1392 =
1393 ================
1394 */
1395
1396 void I_ShutdownMouse (void)
1397 {
1398         if (!mousepresent)
1399           return;
1400
1401         I_ResetMouse ();
1402 }
1403
1404
1405 /*
1406 ================
1407 =
1408 = I_ReadMouse
1409 =
1410 ================
1411 */
1412
1413 void I_ReadMouse (void)
1414 {
1415         event_t ev;
1416
1417 //
1418 // mouse events
1419 //
1420         if (!mousepresent)
1421                 return;
1422
1423         ev.type = ev_mouse;
1424
1425         memset (&dpmiregs,0,sizeof(dpmiregs));
1426         dpmiregs.eax = 3;                               // read buttons / position
1427         DPMIInt (0x33);
1428         ev.data1 = dpmiregs.ebx;
1429
1430         dpmiregs.eax = 11;                              // read counters
1431         DPMIInt (0x33);
1432         ev.data2 = (short)dpmiregs.ecx;
1433         ev.data3 = -(short)dpmiregs.edx;
1434
1435         D_PostEvent (&ev);
1436 }
1437
1438 /*
1439 ============================================================================
1440
1441                                         JOYSTICK
1442
1443 ============================================================================
1444 */
1445
1446 int     joyxl, joyxh, joyyl, joyyh;
1447
1448 boolean WaitJoyButton (void)
1449 {
1450         int             oldbuttons, buttons;
1451
1452         oldbuttons = 0;
1453         do
1454         {
1455                 I_WaitVBL (1);
1456                 buttons =  ((inp(0x201) >> 4)&1)^1;
1457                 if (buttons != oldbuttons)
1458                 {
1459                         oldbuttons = buttons;
1460                         continue;
1461                 }
1462
1463                 if ( (lastpress& 0x7f) == 1 )
1464                 {
1465                         joystickpresent = false;
1466                         return false;
1467                 }
1468         } while ( !buttons);
1469
1470         do
1471         {
1472                 I_WaitVBL (1);
1473                 buttons =  ((inp(0x201) >> 4)&1)^1;
1474                 if (buttons != oldbuttons)
1475                 {
1476                         oldbuttons = buttons;
1477                         continue;
1478                 }
1479
1480                 if ( (lastpress& 0x7f) == 1 )
1481                 {
1482                         joystickpresent = false;
1483                         return false;
1484                 }
1485         } while ( buttons);
1486
1487         return true;
1488 }
1489
1490
1491
1492 /*
1493 ===============
1494 =
1495 = I_StartupJoystick
1496 =
1497 ===============
1498 */
1499
1500 int             basejoyx, basejoyy;
1501
1502 void I_StartupJoystick (void)
1503 {
1504         int     buttons;
1505         int     count;
1506         int     centerx, centery;
1507
1508         joystickpresent = 0;
1509         if ( M_CheckParm ("-nojoy") || !usejoystick )
1510                 return;
1511
1512         if (!I_ReadJoystick ())
1513         {
1514                 joystickpresent = false;
1515                 tprintf ("joystick not found ",0);
1516                 return;
1517         }
1518         printf("joystick found\n");
1519         joystickpresent = true;
1520
1521         printf("CENTER the joystick and press button 1:");
1522         if (!WaitJoyButton ())
1523                 return;
1524         I_ReadJoystick ();
1525         centerx = joystickx;
1526         centery = joysticky;
1527
1528         printf("\nPush the joystick to the UPPER LEFT corner and press button 1:");
1529         if (!WaitJoyButton ())
1530                 return;
1531         I_ReadJoystick ();
1532         joyxl = (centerx + joystickx)/2;
1533         joyyl = (centerx + joysticky)/2;
1534
1535         printf("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
1536         if (!WaitJoyButton ())
1537                 return;
1538         I_ReadJoystick ();
1539         joyxh = (centerx + joystickx)/2;
1540         joyyh = (centery + joysticky)/2;
1541         printf("\n");
1542 }
1543
1544 /*
1545 ===============
1546 =
1547 = I_JoystickEvents
1548 =
1549 ===============
1550 */
1551
1552 void I_JoystickEvents (void)
1553 {
1554         event_t ev;
1555
1556 //
1557 // joystick events
1558 //
1559         if (!joystickpresent)
1560                 return;
1561
1562         I_ReadJoystick ();
1563         ev.type = ev_joystick;
1564         ev.data1 =  ((inp(0x201) >> 4)&15)^15;
1565
1566         if (joystickx < joyxl)
1567                 ev.data2 = -1;
1568         else if (joystickx > joyxh)
1569                 ev.data2 = 1;
1570         else
1571                 ev.data2 = 0;
1572         if (joysticky < joyyl)
1573                 ev.data3 = -1;
1574         else if (joysticky > joyyh)
1575                 ev.data3 = 1;
1576         else
1577                 ev.data3 = 0;
1578
1579         D_PostEvent (&ev);
1580 }
1581
1582
1583
1584 /*
1585 ============================================================================
1586
1587                                         DPMI STUFF
1588
1589 ============================================================================
1590 */
1591
1592 #define REALSTACKSIZE   1024
1593
1594 dpmiregs_t      dpmiregs;
1595
1596 unsigned                realstackseg;
1597
1598 void I_DivException (void);
1599 int I_SetDivException (void);
1600
1601 void DPMIFarCall (void)
1602 {
1603         segread (&segregs);
1604         regs.w.ax = 0x301;
1605         regs.w.bx = 0;
1606         regs.w.cx = 0;
1607         regs.x.edi = (unsigned)&dpmiregs;
1608         segregs.es = segregs.ds;
1609         int386x( DPMI_INT, &regs, &regs, &segregs );
1610 }
1611
1612
1613 void DPMIInt (int i)
1614 {
1615         dpmiregs.ss = realstackseg;
1616         dpmiregs.sp = REALSTACKSIZE-4;
1617
1618         segread (&segregs);
1619         regs.w.ax = 0x300;
1620         regs.w.bx = i;
1621         regs.w.cx = 0;
1622         regs.x.edi = (unsigned)&dpmiregs;
1623         segregs.es = segregs.ds;
1624         int386x( DPMI_INT, &regs, &regs, &segregs );
1625 }
1626
1627
1628 /*
1629 ==============
1630 =
1631 = I_StartupDPMI
1632 =
1633 ==============
1634 */
1635
1636 void I_StartupDPMI (void)
1637 {
1638         extern char __begtext;
1639         extern char ___argc;
1640         int     n,d;
1641
1642 //
1643 // allocate a decent stack for real mode ISRs
1644 //
1645         realstackseg = (int)I_AllocLow (1024) >> 4;
1646
1647 //
1648 // lock the entire program down
1649 //
1650
1651 //      _dpmi_lockregion (&__begtext, &___argc - &__begtext);
1652
1653
1654 //
1655 // catch divide by 0 exception
1656 //
1657 #if 0
1658         segread(&segregs);
1659         regs.w.ax = 0x0203;             // DPMI set processor exception handler vector
1660         regs.w.bx = 0;                  // int 0
1661         regs.w.cx = segregs.cs;
1662         regs.x.edx = (int)&I_DivException;
1663  printf ("%x : %x\n",regs.w.cx, regs.x.edx);
1664         int386( DPMI_INT, &regs, &regs);
1665 #endif
1666
1667 #if 0
1668         n = I_SetDivException ();
1669         printf ("return: %i\n",n);
1670         n = 100;
1671         d = 0;
1672    printf ("100 / 0 = %i\n",n/d);
1673
1674 exit (1);
1675 #endif
1676 }
1677
1678
1679
1680 /*
1681 ============================================================================
1682
1683                                         TIMER INTERRUPT
1684
1685 ============================================================================
1686 */
1687
1688 void (__interrupt __far *oldtimerisr) ();
1689
1690
1691 void IO_ColorBlack (int r, int g, int b)
1692 {
1693 _outbyte (PEL_WRITE_ADR,0);
1694 _outbyte(PEL_DATA,r);
1695 _outbyte(PEL_DATA,g);
1696 _outbyte(PEL_DATA,b);
1697 }
1698
1699
1700 /*
1701 ================
1702 =
1703 = IO_TimerISR
1704 =
1705 ================
1706 */
1707
1708 //void __interrupt IO_TimerISR (void)
1709
1710 void __interrupt __far IO_TimerISR (void)
1711 {
1712         ticcount++;
1713         _outbyte(0x20,0x20);                            // Ack the interrupt
1714 }
1715
1716 /*
1717 =====================
1718 =
1719 = IO_SetTimer0
1720 =
1721 = Sets system timer 0 to the specified speed
1722 =
1723 =====================
1724 */
1725
1726 void IO_SetTimer0(int speed)
1727 {
1728         if (speed > 0 && speed < 150)
1729                 I_Error ("INT_SetTimer0: %i is a bad value",speed);
1730
1731         _outbyte(0x43,0x36);                            // Change timer 0
1732         _outbyte(0x40,speed);
1733         _outbyte(0x40,speed >> 8);
1734 }
1735
1736
1737
1738 /*
1739 ===============
1740 =
1741 = IO_StartupTimer
1742 =
1743 ===============
1744 */
1745
1746 void IO_StartupTimer (void)
1747 {
1748         oldtimerisr = _dos_getvect(TIMERINT);
1749
1750         _dos_setvect (0x8000 | TIMERINT, IO_TimerISR);
1751         IO_SetTimer0 (VBLCOUNTER);
1752 }
1753
1754 void IO_ShutdownTimer (void)
1755 {
1756         if (oldtimerisr)
1757         {
1758                 IO_SetTimer0 (0);              // back to 18.4 ips
1759                 _dos_setvect (TIMERINT, oldtimerisr);
1760         }
1761 }
1762
1763 //===========================================================================
1764
1765
1766 /*
1767 ===============
1768 =
1769 = I_Init
1770 =
1771 = hook interrupts and set graphics mode
1772 =
1773 ===============
1774 */
1775
1776 void I_Init (void)
1777 {
1778         extern void I_StartupTimer(void);
1779
1780         novideo = M_CheckParm("novideo");
1781         tprintf("I_StartupDPMI",1);
1782         I_StartupDPMI();
1783         tprintf("I_StartupMouse ",1);
1784         I_StartupMouse();
1785 //      tprintf("I_StartupJoystick ",1);
1786 //      I_StartupJoystick();
1787 //      tprintf("I_StartupKeyboard ",1);
1788 //      I_StartupKeyboard();
1789         tprintf("S_Init... ",1);
1790         S_Init();
1791         //IO_StartupTimer();
1792         S_Start();
1793 }
1794
1795
1796 /*
1797 ===============
1798 =
1799 = I_Shutdown
1800 =
1801 = return to default system state
1802 =
1803 ===============
1804 */
1805
1806 void I_Shutdown (void)
1807 {
1808         I_ShutdownGraphics ();
1809         IO_ShutdownTimer ();
1810         S_ShutDown ();
1811         I_ShutdownMouse ();
1812         I_ShutdownKeyboard ();
1813
1814         IO_SetTimer0 (0);
1815 }
1816
1817
1818 /*
1819 ================
1820 =
1821 = I_Error
1822 =
1823 ================
1824 */
1825
1826 void I_Error (char *error, ...)
1827 {
1828         union REGS regs;
1829
1830         va_list argptr;
1831
1832         D_QuitNetGame ();
1833         I_Shutdown ();
1834         va_start (argptr,error);
1835         regs.x.eax = 0x3;
1836         int386(0x10, &regs, &regs);
1837         vprintf (error,argptr);
1838         va_end (argptr);
1839         printf ("\n");
1840         exit (1);
1841 }
1842
1843 //--------------------------------------------------------------------------
1844 //
1845 // I_Quit
1846 //
1847 // Shuts down net game, saves defaults, prints the exit text message,
1848 // goes to text mode, and exits.
1849 //
1850 //--------------------------------------------------------------------------
1851
1852 void I_Quit(void)
1853 {
1854         byte *scr;
1855         char *lumpName;
1856         int r;
1857
1858         D_QuitNetGame();
1859         M_SaveDefaults();
1860         scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
1861         I_Shutdown();
1862         memcpy((void *)0xb8000, scr, 80*25*2);
1863         regs.w.ax = 0x0200;
1864         regs.h.bh = 0;
1865         regs.h.dl = 0;
1866         regs.h.dh = 23;
1867         int386(0x10, (const union REGS *)&regs, &regs); // Set text pos
1868         _settextposition(24, 1);
1869         exit(0);
1870 }
1871
1872 /*
1873 ===============
1874 =
1875 = I_ZoneBase
1876 =
1877 ===============
1878 */
1879
1880 byte *I_ZoneBase (int *size)
1881 {
1882         int             meminfo[32];
1883         int             heap;
1884         int             i;
1885         int                             block;
1886         byte                    *ptr;
1887
1888         memset (meminfo,0,sizeof(meminfo));
1889         segread(&segregs);
1890         segregs.es = segregs.ds;
1891         regs.w.ax = 0x500;      // get memory info
1892         regs.x.edi = (int)&meminfo;
1893         int386x( 0x31, &regs, &regs, &segregs );
1894
1895         heap = meminfo[0];
1896         printf ("DPMI memory: 0x%x, ",heap);
1897
1898         do
1899         {
1900                 heap -= 0x10000;                // leave 64k alone
1901                 if (heap > 0x800000)
1902                         heap = 0x800000;
1903                 ptr = malloc (heap);
1904         } while (!ptr);
1905
1906         printf ("0x%x allocated for zone\n", heap);
1907         if (heap < 0x180000)
1908                 I_Error ("Insufficient DPMI memory!");
1909 #if 0
1910         regs.w.ax = 0x501;      // allocate linear block
1911         regs.w.bx = heap>>16;
1912         regs.w.cx = heap&0xffff;
1913         int386( 0x31, &regs, &regs);
1914         if (regs.w.cflag)
1915                 I_Error ("Couldn't allocate DPMI memory!");
1916
1917         block = (regs.w.si << 16) + regs.w.di;
1918 #endif
1919
1920         *size = heap;
1921         return ptr;
1922 }
1923
1924 /*
1925 =============================================================================
1926
1927                                         DISK ICON FLASHING
1928
1929 =============================================================================
1930 */
1931
1932 void I_InitDiskFlash (void)
1933 {
1934 #if 0
1935         void    *pic;
1936         byte    *temp;
1937
1938         pic = W_CacheLumpName ("STDISK",PU_CACHE);
1939         temp = destscreen;
1940         destscreen = (byte *)0xac000;
1941         V_DrawPatchDirect (SCREENWIDTH-16,SCREENHEIGHT-16,0,pic);
1942         destscreen = temp;
1943 #endif
1944 }
1945
1946 // draw disk icon
1947 void I_BeginRead (void)
1948 {
1949 #if 0
1950         byte    *src,*dest;
1951         int             y;
1952
1953         if (!grmode)
1954                 return;
1955
1956 // write through all planes
1957         outp (SC_INDEX,SC_MAPMASK);
1958         outp (SC_INDEX+1,15);
1959 // set write mode 1
1960         outp (GC_INDEX,GC_MODE);
1961         outp (GC_INDEX+1,inp(GC_INDEX+1)|1);
1962
1963 // copy to backup
1964         src = currentscreen + 184*80 + 304/4;
1965         dest = (byte *)0xac000 + 184*80 + 288/4;
1966         for (y=0 ; y<16 ; y++)
1967         {
1968                 dest[0] = src[0];
1969                 dest[1] = src[1];
1970                 dest[2] = src[2];
1971                 dest[3] = src[3];
1972                 src += 80;
1973                 dest += 80;
1974         }
1975
1976 // copy disk over
1977         dest = currentscreen + 184*80 + 304/4;
1978         src = (byte *)0xac000 + 184*80 + 304/4;
1979         for (y=0 ; y<16 ; y++)
1980         {
1981                 dest[0] = src[0];
1982                 dest[1] = src[1];
1983                 dest[2] = src[2];
1984                 dest[3] = src[3];
1985                 src += 80;
1986                 dest += 80;
1987         }
1988
1989
1990 // set write mode 0
1991         outp (GC_INDEX,GC_MODE);
1992         outp (GC_INDEX+1,inp(GC_INDEX+1)&~1);
1993 #endif
1994 }
1995
1996 // erase disk icon
1997 void I_EndRead (void)
1998 {
1999 #if 0
2000         byte    *src,*dest;
2001         int             y;
2002
2003         if (!grmode)
2004                 return;
2005
2006 // write through all planes
2007         outp (SC_INDEX,SC_MAPMASK);
2008         outp (SC_INDEX+1,15);
2009 // set write mode 1
2010         outp (GC_INDEX,GC_MODE);
2011         outp (GC_INDEX+1,inp(GC_INDEX+1)|1);
2012
2013
2014 // copy disk over
2015         dest = currentscreen + 184*80 + 304/4;
2016         src = (byte *)0xac000 + 184*80 + 288/4;
2017         for (y=0 ; y<16 ; y++)
2018         {
2019                 dest[0] = src[0];
2020                 dest[1] = src[1];
2021                 dest[2] = src[2];
2022                 dest[3] = src[3];
2023                 src += 80;
2024                 dest += 80;
2025         }
2026
2027 // set write mode 0
2028         outp (GC_INDEX,GC_MODE);
2029         outp (GC_INDEX+1,inp(GC_INDEX+1)&~1);
2030 #endif
2031 }
2032
2033
2034
2035 /*
2036 =============
2037 =
2038 = I_AllocLow
2039 =
2040 =============
2041 */
2042
2043 byte *I_AllocLow (int length)
2044 {
2045         byte    *mem;
2046
2047         // DPMI call 100h allocates DOS memory
2048         segread(&segregs);
2049         regs.w.ax = 0x0100;          // DPMI allocate DOS memory
2050         regs.w.bx = (length+15) / 16;
2051         int386( DPMI_INT, &regs, &regs);
2052 //      segment = regs.w.ax;
2053 //   selector = regs.w.dx;
2054         if (regs.w.cflag != 0)
2055                 I_Error ("I_AllocLow: DOS alloc of %i failed, %i free",
2056                         length, regs.w.bx*16);
2057
2058
2059         mem = (void *) ((regs.x.eax & 0xFFFF) << 4);
2060
2061         memset (mem,0,length);
2062         return mem;
2063 }
2064
2065 /*
2066 ============================================================================
2067
2068                                                 NETWORKING
2069
2070 ============================================================================
2071 */
2072
2073 /* // FUCKED LINES
2074 typedef struct
2075 {
2076         char    priv[508];
2077 } doomdata_t;
2078 */ // FUCKED LINES
2079
2080 #define DOOMCOM_ID              0x12345678l
2081
2082 /* // FUCKED LINES
2083 typedef struct
2084 {
2085         long    id;
2086         short   intnum;                 // DOOM executes an int to execute commands
2087
2088 // communication between DOOM and the driver
2089         short   command;                // CMD_SEND or CMD_GET
2090         short   remotenode;             // dest for send, set by get (-1 = no packet)
2091         short   datalength;             // bytes in doomdata to be sent
2092
2093 // info common to all nodes
2094         short   numnodes;               // console is allways node 0
2095         short   ticdup;                 // 1 = no duplication, 2-5 = dup for slow nets
2096         short   extratics;              // 1 = send a backup tic in every packet
2097         short   deathmatch;             // 1 = deathmatch
2098         short   savegame;               // -1 = new game, 0-5 = load savegame
2099         short   episode;                // 1-3
2100         short   map;                    // 1-9
2101         short   skill;                  // 1-5
2102
2103 // info specific to this node
2104         short   consoleplayer;
2105         short   numplayers;
2106         short   angleoffset;    // 1 = left, 0 = center, -1 = right
2107         short   drone;                  // 1 = drone
2108
2109 // packet data to be sent
2110         doomdata_t      data;
2111 } doomcom_t;
2112 */ // FUCKED LINES
2113
2114 extern  doomcom_t               *doomcom;
2115
2116 /*
2117 ====================
2118 =
2119 = I_InitNetwork
2120 =
2121 ====================
2122 */
2123
2124 void I_InitNetwork (void)
2125 {
2126         int             i;
2127
2128         i = M_CheckParm ("-net");
2129         if (!i)
2130         {
2131         //
2132         // single player game
2133         //
2134                 doomcom = malloc (sizeof (*doomcom) );
2135                 memset (doomcom, 0, sizeof(*doomcom) );
2136                 netgame = false;
2137                 doomcom->id = DOOMCOM_ID;
2138                 doomcom->numplayers = doomcom->numnodes = 1;
2139                 doomcom->deathmatch = false;
2140                 doomcom->consoleplayer = 0;
2141                 doomcom->ticdup = 1;
2142                 doomcom->extratics = 0;
2143                 return;
2144         }
2145
2146         netgame = true;
2147         doomcom = (doomcom_t *)atoi(myargv[i+1]);
2148 //DEBUG
2149 doomcom->skill = startskill;
2150 doomcom->episode = startepisode;
2151 doomcom->map = startmap;
2152 doomcom->deathmatch = deathmatch;
2153
2154 }
2155
2156 void I_NetCmd (void)
2157 {
2158         if (!netgame)
2159                 I_Error ("I_NetCmd when not in netgame");
2160         DPMIInt (doomcom->intnum);
2161 }
2162
2163 int i_Vector;
2164 externdata_t *i_ExternData;
2165 boolean useexterndriver;
2166
2167 //=========================================================================
2168 //
2169 // I_CheckExternDriver
2170 //
2171 //              Checks to see if a vector, and an address for an external driver
2172 //                      have been passed.
2173 //=========================================================================
2174
2175 void I_CheckExternDriver(void)
2176 {
2177         int i;
2178
2179         if(!(i = M_CheckParm("-externdriver")))
2180         {
2181                 return;
2182         }
2183         i_ExternData = (externdata_t *)atoi(myargv[i+1]);
2184         i_Vector = i_ExternData->vector;
2185
2186         useexterndriver = true;
2187 }
2188
2189 //=========================================================================
2190 //
2191 // I_ReadExternDriver
2192 //
2193 //              calls the external interrupt, which should then update i_ExternDriver
2194 //=========================================================================
2195
2196 void I_ReadExternDriver(void)
2197 {
2198         event_t ev;
2199
2200         if(useexterndriver)
2201         {
2202                 DPMIInt(i_Vector);
2203         }
2204 }