1 //**************************************************************************
5 //**************************************************************************
13 #include "p_local.h" // for P_AproxDistance
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)
27 #define KEY_LSHIFT 0xfe
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)
36 extern void **lumpcache;
38 extern void I_StartupMouse();
39 extern void I_ShutdownGraphics();
42 externdata_t *i_ExternData;
43 boolean useexterndriver;
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);
63 ===============================================================================
67 ===============================================================================
70 //static channel_t channel[MAX_CHANNELS];
72 //static int rs; //the current registered song.
78 extern sfxinfo_t S_sfx[];
79 extern musicinfo_t S_music[];
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;
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;
96 extern int startepisode;
101 boolean S_StopSoundID(int sound_id, int priority);
103 //==========================================================================
107 //==========================================================================
113 S_StartSong((gameepisode-1)*9 + gamemap-1, true);
116 for(i=0; i < snd_Channels; i++)
118 if(Channel[i].handle)
120 S_StopSound(Channel[i].mo);
123 memset(Channel, 0, 8*sizeof(channel_t));
126 //==========================================================================
130 //==========================================================================
132 void S_StartSong(int song, boolean loop)
135 { // don't replay an old song
140 I_StopSong(RegisteredSong);
141 I_UnRegisterSong(RegisteredSong);
142 Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
144 if(song < mus_e1m1 || song > NUMMUSIC)
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.
155 //==========================================================================
159 //==========================================================================
161 void S_StartSound(mobj_t *origin, int sound_id)
171 static int sndcount = 0;
174 if(sound_id==0 || snd_MaxVolume == 0)
178 // origin = players[consoleplayer].mo;
181 // calculate the distance before other stuff so that we can throw out
182 // sounds that are beyond the hearing range.
185 absx = abs(origin->x-players[consoleplayer].mo->x);
186 absy = abs(origin->y-players[consoleplayer].mo->y);
190 dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
192 // dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS;
194 if(dist >= MAX_SND_DIST)
196 // dist = MAX_SND_DIST - 1;
197 return; //sound is beyond the hearing range...
203 priority = S_sfx[sound_id].priority;
204 priority *= (10 - (dist/160));
205 if(!S_StopSoundID(sound_id, priority))
207 return; // other sounds have greater priority
209 for(i=0; i<snd_Channels; i++)
211 if(!origin || origin->player)
214 break; // let the player have more than one sound.
216 if(origin == Channel[i].mo)
217 { // only allow other mobjs one sound
218 S_StopSound(Channel[i].mo);
222 if(i >= snd_Channels)
224 if(sound_id >= sfx_wind)
226 if(AmbChan != -1 && S_sfx[sound_id].priority <=
227 S_sfx[Channel[AmbChan].sound_id].priority)
229 return; //ambient channel already in use
236 for(i=0; i<snd_Channels; i++)
238 if(Channel[i].mo == NULL)
243 if(i >= snd_Channels)
245 //look for a lower priority sound to replace.
247 if(sndcount >= snd_Channels)
251 for(chan=0; chan < snd_Channels; chan++)
253 i = (sndcount+chan)%snd_Channels;
254 if(priority >= Channel[i].priority)
256 chan = -1; //denote that sound should be replaced.
262 return; //no free channels.
264 else //replace the lower priority sound.
266 if(Channel[i].handle)
268 if(I_SoundIsPlaying(Channel[i].handle))
270 I_StopSound(Channel[i].handle);
272 if(S_sfx[Channel[i].sound_id].usefulness > 0)
274 S_sfx[Channel[i].sound_id].usefulness--;
285 if(S_sfx[sound_id].lumpnum == 0)
287 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
289 if(S_sfx[sound_id].snd_ptr == NULL)
291 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
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];
299 if(!origin || origin == players[consoleplayer].mo)
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);
309 angle = (angle-viewangle)>>24;
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)
326 if(S_sfx[sound_id].usefulness == -1)
328 S_sfx[sound_id].usefulness = 1;
332 S_sfx[sound_id].usefulness++;
336 //==========================================================================
338 // S_StartSoundAtVolume
340 //==========================================================================
341 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
345 if(sound_id == 0 || snd_MaxVolume == 0)
349 origin = players[displayplayer].mo;
356 volume = (volume*(snd_MaxVolume+1)*8)>>7;
358 // no priority checking, as ambient sounds would be the LOWEST.
359 for(i=0; i<snd_Channels; i++)
361 if(Channel[i].mo == NULL)
366 if(i >= snd_Channels)
370 if(S_sfx[sound_id].lumpnum == 0)
372 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
374 if(S_sfx[sound_id].snd_ptr == NULL)
376 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
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)
386 S_sfx[sound_id].usefulness = 1;
390 S_sfx[sound_id].usefulness++;
393 //==========================================================================
397 //==========================================================================
399 boolean S_StopSoundID(int sound_id, int priority)
402 int lp; //least priority
405 if(S_sfx[sound_id].numchannels == -1)
409 lp = -1; //denote the argument sound_id
411 for(i=0; i<snd_Channels; i++)
413 if(Channel[i].sound_id == sound_id && Channel[i].mo)
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
419 priority = Channel[i].priority;
423 if(found < S_sfx[sound_id].numchannels)
429 return(false); // don't replace any sounds
431 if(Channel[lp].handle)
433 if(I_SoundIsPlaying(Channel[lp].handle))
435 I_StopSound(Channel[lp].handle);
437 if(S_sfx[Channel[lp].sound_id].usefulness > 0)
439 S_sfx[Channel[lp].sound_id].usefulness--;
441 Channel[lp].mo = NULL;
446 //==========================================================================
450 //==========================================================================
452 void S_StopSound(mobj_t *origin)
456 for(i=0;i<snd_Channels;i++)
458 if(Channel[i].mo == origin)
460 I_StopSound(Channel[i].handle);
461 if(S_sfx[Channel[i].sound_id].usefulness > 0)
463 S_sfx[Channel[i].sound_id].usefulness--;
465 Channel[i].handle = 0;
466 Channel[i].mo = NULL;
475 //==========================================================================
479 //==========================================================================
481 void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
485 for(i=0;i<snd_Channels;i++)
487 if(Channel[i].mo == oldactor)
488 Channel[i].mo = newactor;
492 //==========================================================================
496 //==========================================================================
498 void S_PauseSound(void)
500 I_PauseSong(RegisteredSong);
503 //==========================================================================
507 //==========================================================================
509 void S_ResumeSound(void)
511 I_ResumeSong(RegisteredSong);
514 //==========================================================================
518 //==========================================================================
520 void S_UpdateSounds(mobj_t *listener)
529 listener = players[consoleplayer].mo;
530 if(snd_MaxVolume == 0)
535 if(NextCleanup < gametic)
537 for(i = 0; i < NUMSFX; i++)
539 if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
541 if(lumpcache[S_sfx[i].lumpnum])
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],
550 S_sfx[i].usefulness = -1;
551 S_sfx[i].snd_ptr = NULL;
554 // Note, heretic does this every second (gametic+35)
555 NextCleanup = gametic+35*30; // every 30 seconds
557 for(i=0;i<snd_Channels;i++)
559 if(!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
563 if(!I_SoundIsPlaying(Channel[i].handle))
565 if(S_sfx[Channel[i].sound_id].usefulness > 0)
567 S_sfx[Channel[i].sound_id].usefulness--;
569 Channel[i].handle = 0;
570 Channel[i].mo = NULL;
571 Channel[i].sound_id = 0;
577 if(Channel[i].mo == NULL || Channel[i].sound_id == 0
578 || Channel[i].mo == listener)
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);
589 if(dist >= MAX_SND_DIST)
591 S_StopSound(Channel[i].mo);
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;
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;
615 //==========================================================================
619 //==========================================================================
623 SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
629 I_SetChannels(snd_Channels);
630 I_SetMusicVolume(snd_MusicVolume);
631 S_SetMaxVolume(true);
634 //==========================================================================
638 //==========================================================================
640 void S_GetChannelInfo(SoundInfo_t *s)
645 s->channelCount = snd_Channels;
646 s->musicVolume = snd_MusicVolume;
647 s->soundVolume = snd_MaxVolume;
648 for(i = 0; i < snd_Channels; 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)
660 void S_SetMaxVolume(boolean fullprocess)
666 SoundCurve[0] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE))*(snd_MaxVolume*8))>>7;
670 for(i = 0; i < MAX_SND_DIST; i++)
672 SoundCurve[i] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+i)*(snd_MaxVolume*8))>>7;
677 //==========================================================================
681 //==========================================================================
683 void S_SetMusicVolume(void)
685 I_SetMusicVolume(snd_MusicVolume);
686 if(snd_MusicVolume == 0)
688 I_PauseSong(RegisteredSong);
694 I_ResumeSong(RegisteredSong);
698 //==========================================================================
702 //==========================================================================
704 void S_ShutDown(void)
709 I_StopSong(RegisteredSong);
710 I_UnRegisterSong(RegisteredSong);
715 //==================================================
720 boolean novideo; // if true, stay in text mode for debugging
723 //==========================================================================
726 static long _startSec;
728 void I_StartupTimer(void)
731 gettimeofday( &tv, 0 );
732 _startSec = tv.tv_sec;
735 //--------------------------------------------------------------------------
739 // Returns time in 1/35th second tics.
741 //--------------------------------------------------------------------------
746 gettimeofday( &tv, 0 );
748 //printf( "GT: %lx %lx\n", tv.tv_sec, tv.tv_usec );
750 // ticcount = ((tv.tv_sec * 1000000) + tv.tv_usec) / 28571;
751 ticcount = ((tv.tv_sec - _startSec) * 35) + (tv.tv_usec / 28571);
757 ============================================================================
761 ============================================================================
764 //==================================================
768 //==================================================
770 extern int usejoystick;
771 boolean joystickpresent;
772 unsigned joystickx, joysticky;
774 // returns false if not connected
775 boolean I_ReadJoystick (void)
781 int joyxl, joyxh, joyyl, joyyh;
783 boolean WaitJoyButton (void)
786 int oldbuttons, buttons;
792 buttons = ((inp(0x201) >> 4)&1)^1;
793 if (buttons != oldbuttons)
795 oldbuttons = buttons;
799 if ( (lastpress& 0x7f) == 1 )
801 joystickpresent = false;
809 buttons = ((inp(0x201) >> 4)&1)^1;
810 if (buttons != oldbuttons)
812 oldbuttons = buttons;
816 if ( (lastpress& 0x7f) == 1 )
818 joystickpresent = false;
837 int basejoyx, basejoyy;
839 void I_StartupJoystick (void)
841 int centerx, centery;
844 if ( M_CheckParm ("-nojoy") || !usejoystick )
847 if (!I_ReadJoystick ())
849 joystickpresent = false;
850 tprintf ("joystick not found\n ",1);
853 tprintf ("joystick found\n",1);
854 joystickpresent = true;
856 tprintf ("CENTER the joystick and press button 1:",1);
857 if (!WaitJoyButton ())
863 tprintf("\nPush the joystick to the UPPER LEFT corner and press button 1:",1);
864 if (!WaitJoyButton ())
867 joyxl = (centerx + joystickx)/2;
868 joyyl = (centerx + joysticky)/2;
870 tprintf("\nPush the joystick to the LOWER RIGHT corner and press button 1:",1);
871 if (!WaitJoyButton ())
874 joyxh = (centerx + joystickx)/2;
875 joyyh = (centery + joysticky)/2;
887 void I_JoystickEvents (void)
894 if (!joystickpresent)
898 ev.type = ev_joystick;
899 ev.data1 = 0; //((inp(0x201) >> 4)&15)^15;
901 if (joystickx < joyxl)
903 else if (joystickx > joyxh)
907 if (joysticky < joyyl)
909 else if (joysticky > joyyh)
926 void I_StartFrame (void)
933 ============================================================================
937 ============================================================================
940 void I_DivException (void);
941 int I_SetDivException (void);
946 ============================================================================
950 ============================================================================
959 = hook interrupts and set graphics mode
966 void I_StartupTimer(void);
968 novideo = M_CheckParm("novideo");
970 // tprintf("I_StartupJoystick ",1);
971 // I_StartupJoystick();
972 tprintf("S_Init... ",1);
985 = return to default system state
990 void I_ShutdownNet (void)
995 void I_Shutdown (void)
997 I_ShutdownGraphics ();
1011 void I_Error (char *error, ...)
1017 va_start (argptr,error);
1018 vprintf (error, argptr);
1024 //--------------------------------------------------------------------------
1028 // Shuts down net game, saves defaults, prints the exit text message,
1029 // goes to text mode, and exits.
1031 //--------------------------------------------------------------------------
1033 void put_dos2ansi (byte attrib)
1035 byte fore,back,blink=0,intens=0;
1036 int table[] = {30,34,32,36,31,35,33,37};
1038 fore = attrib&15; // bits 0-3
1039 back = attrib&112; // bits 4-6
1040 blink = attrib&128; // bit 7
1042 // Fix background, blink is either on or off.
1051 // Convert fore/back
1053 back = table[back] + 10;
1057 printf ("\033[%d;5;%dm\033[%dm", intens, fore, back);
1059 printf ("\033[%d;25;%dm\033[%dm", intens, fore, back);
1071 scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
1073 memcpy((void *)0xb8000, scr, 80*25*2);
1078 int386(0x10, (const union REGS *)®s, ®s); // Set text pos
1079 _settextposition(24, 1);
1081 for (i=0; i< 80*25*2; i+=2) {
1082 put_dos2ansi(scr[2+i+1]);
1085 // Cleanup after all that ANSI stuff
1086 printf ("\033[m\n");
1100 byte *I_ZoneBase (int *size)
1103 int heap = 0x800000;
1105 ptr = malloc ( heap );
1108 I_Error (" Insufficient DPMI memory!");
1122 byte *I_AllocLow (int length)
1124 return malloc( length );
1128 ============================================================================
1132 ============================================================================
1142 #define DOOMCOM_ID 0x12345678l
1148 short intnum; // DOOM executes an int to execute commands
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
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
1165 // info specific to this node
1166 short consoleplayer;
1168 short angleoffset; // 1 = left, 0 = center, -1 = right
1169 short drone; // 1 = drone
1171 // packet data to be sent
1176 extern doomcom_t *doomcom;
1179 ====================
1183 ====================
1186 void I_InitNetwork (void)
1190 i = M_CheckParm ("-net");
1194 // single player game
1196 doomcom = malloc (sizeof (*doomcom) );
1197 memset (doomcom, 0, sizeof(*doomcom) );
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;
1208 doomcom = (doomcom_t *)atoi(myargv[i+1]);
1210 doomcom->skill = startskill;
1211 doomcom->episode = startepisode;
1212 doomcom->map = startmap;
1213 doomcom->deathmatch = deathmatch;
1216 void I_NetCmd (void)
1219 I_Error ("I_NetCmd when not in netgame");
1222 //=========================================================================
1224 // I_CheckExternDriver
1226 // Checks to see if a vector, and an address for an external driver
1227 // have been passed.
1228 //=========================================================================
1230 void I_CheckExternDriver(void)
1234 if(!(i = M_CheckParm("-externdriver")))
1238 i_ExternData = (externdata_t *)atoi(myargv[i+1]);
1239 i_Vector = i_ExternData->vector;
1241 useexterndriver = true;
1245 int main( int argc, char** argv )
1253 fixed_t FixedMul (fixed_t a, fixed_t b)
1255 return ((long long) a * (long long) b) >> 16;
1258 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
1262 c = ((double)a) / ((double)b) * FRACUNIT;
1264 if (c >= 2147483648.0 || c < -2147483648.0)
1265 I_Error("FixedDiv: divide by zero");