1 //**************************************************************************
5 //**************************************************************************
13 #include "p_local.h" // for P_AproxDistance
20 #define stricmp strcasecmp
21 #define DEFAULT_ARCHIVEPATH "o:\\sound\\archive\\"
22 #define PRIORITY_MAX_ADJUST 10
23 #define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
25 #define KEY_LSHIFT 0xfe
27 #define KEY_INS (0x80+0x52)
28 #define KEY_DEL (0x80+0x53)
29 #define KEY_PGUP (0x80+0x49)
30 #define KEY_PGDN (0x80+0x51)
31 #define KEY_HOME (0x80+0x47)
32 #define KEY_END (0x80+0x4f)
34 extern void **lumpcache;
36 extern void I_StartupMouse();
37 extern void I_ShutdownGraphics();
40 externdata_t *i_ExternData;
41 boolean useexterndriver;
43 // Function Declarations
44 void I_StopSong(int handle);
45 void I_UnRegisterSong(int handle);
46 int I_RegisterSong (void *data);
47 void I_PlaySong(int handle, boolean looping);
48 int I_SoundIsPlaying (int handle);
49 void I_StopSound (int handle);
50 int I_GetSfxLumpNum (sfxinfo_t *sound);
51 int I_StartSound( int id, void* data, int vol, int sep, int pitch, int priority);
52 void I_PauseSong(int handle);
53 void I_ResumeSong(int handle);
54 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
55 void I_StartupSound (void);
56 void I_SetChannels(int channels);
57 void I_SetMusicVolume(int volume);
58 void I_ShutdownSound (void);
61 ===============================================================================
65 ===============================================================================
68 //static channel_t channel[MAX_CHANNELS];
70 //static int rs; //the current registered song.
76 extern sfxinfo_t S_sfx[];
77 extern musicinfo_t S_music[];
79 static channel_t Channel[MAX_CHANNELS];
80 static int RegisteredSong; //the current registered song.
81 static int NextCleanup;
82 static boolean MusicPaused;
83 static int Mus_Song = -1;
84 static int Mus_LumpNum;
85 static void *Mus_SndPtr;
86 static byte *SoundCurve;
88 extern int snd_MusicDevice;
89 extern int snd_SfxDevice;
90 extern int snd_MaxVolume;
91 extern int snd_MusicVolume;
92 extern int snd_Channels;
94 extern int startepisode;
99 boolean S_StopSoundID(int sound_id, int priority);
101 //==========================================================================
105 //==========================================================================
111 S_StartSong((gameepisode-1)*9 + gamemap-1, true);
114 for(i=0; i < snd_Channels; i++)
116 if(Channel[i].handle)
118 S_StopSound(Channel[i].mo);
121 memset(Channel, 0, 8*sizeof(channel_t));
124 //==========================================================================
128 //==========================================================================
130 void S_StartSong(int song, boolean loop)
133 { // don't replay an old song
138 I_StopSong(RegisteredSong);
139 I_UnRegisterSong(RegisteredSong);
140 Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
142 if(song < mus_e1m1 || song > NUMMUSIC)
146 Mus_LumpNum = W_GetNumForName(S_music[song].name);
147 Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
148 RegisteredSong = I_RegisterSong(Mus_SndPtr);
149 I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
153 //==========================================================================
157 //==========================================================================
159 void S_StartSound(mobj_t *origin, int sound_id)
169 static int sndcount = 0;
172 if(sound_id==0 || snd_MaxVolume == 0)
176 // origin = players[consoleplayer].mo;
179 // calculate the distance before other stuff so that we can throw out
180 // sounds that are beyond the hearing range.
183 absx = abs(origin->x-players[consoleplayer].mo->x);
184 absy = abs(origin->y-players[consoleplayer].mo->y);
188 dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
190 // dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS;
192 if(dist >= MAX_SND_DIST)
194 // dist = MAX_SND_DIST - 1;
195 return; //sound is beyond the hearing range...
201 priority = S_sfx[sound_id].priority;
202 priority *= (10 - (dist/160));
203 if(!S_StopSoundID(sound_id, priority))
205 return; // other sounds have greater priority
207 for(i=0; i<snd_Channels; i++)
209 if(!origin || origin->player)
212 break; // let the player have more than one sound.
214 if(origin == Channel[i].mo)
215 { // only allow other mobjs one sound
216 S_StopSound(Channel[i].mo);
220 if(i >= snd_Channels)
222 if(sound_id >= sfx_wind)
224 if(AmbChan != -1 && S_sfx[sound_id].priority <=
225 S_sfx[Channel[AmbChan].sound_id].priority)
227 return; //ambient channel already in use
234 for(i=0; i<snd_Channels; i++)
236 if(Channel[i].mo == NULL)
241 if(i >= snd_Channels)
243 //look for a lower priority sound to replace.
245 if(sndcount >= snd_Channels)
249 for(chan=0; chan < snd_Channels; chan++)
251 i = (sndcount+chan)%snd_Channels;
252 if(priority >= Channel[i].priority)
254 chan = -1; //denote that sound should be replaced.
260 return; //no free channels.
262 else //replace the lower priority sound.
264 if(Channel[i].handle)
266 if(I_SoundIsPlaying(Channel[i].handle))
268 I_StopSound(Channel[i].handle);
270 if(S_sfx[Channel[i].sound_id].usefulness > 0)
272 S_sfx[Channel[i].sound_id].usefulness--;
283 if(S_sfx[sound_id].lumpnum == 0)
285 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
287 if(S_sfx[sound_id].snd_ptr == NULL)
289 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
293 // calculate the volume based upon the distance from the sound origin.
294 // vol = (snd_MaxVolume*16 + dist*(-snd_MaxVolume*16)/MAX_SND_DIST)>>9;
295 vol = SoundCurve[dist];
297 if(!origin || origin == players[consoleplayer].mo)
303 angle = R_PointToAngle2(players[consoleplayer].mo->x,
304 // players[consoleplayer].mo->y, Channel[i].mo->x, Channel[i].mo->y);
305 players[displayplayer].mo->y, origin->x, origin->y);
307 angle = (angle-viewangle)>>24;
315 Channel[i].pitch = (byte)(127+(M_Random()&7)-(M_Random()&7));
316 Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol, sep, Channel[i].pitch, 0);
317 Channel[i].mo = origin;
318 Channel[i].sound_id = sound_id;
319 Channel[i].priority = priority;
320 if(sound_id >= sfx_wind)
324 if(S_sfx[sound_id].usefulness == -1)
326 S_sfx[sound_id].usefulness = 1;
330 S_sfx[sound_id].usefulness++;
334 //==========================================================================
336 // S_StartSoundAtVolume
338 //==========================================================================
339 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
343 if(sound_id == 0 || snd_MaxVolume == 0)
347 origin = players[displayplayer].mo;
354 volume = (volume*(snd_MaxVolume+1)*8)>>7;
356 // no priority checking, as ambient sounds would be the LOWEST.
357 for(i=0; i<snd_Channels; i++)
359 if(Channel[i].mo == NULL)
364 if(i >= snd_Channels)
368 if(S_sfx[sound_id].lumpnum == 0)
370 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
372 if(S_sfx[sound_id].snd_ptr == NULL)
374 S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
377 Channel[i].pitch = (byte)(127-(M_Random()&3)+(M_Random()&3));
378 Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, volume, 128, Channel[i].pitch, 0);
379 Channel[i].mo = origin;
380 Channel[i].sound_id = sound_id;
381 Channel[i].priority = 1; //super low priority.
382 if(S_sfx[sound_id].usefulness == -1)
384 S_sfx[sound_id].usefulness = 1;
388 S_sfx[sound_id].usefulness++;
391 //==========================================================================
395 //==========================================================================
397 boolean S_StopSoundID(int sound_id, int priority)
400 int lp; //least priority
403 if(S_sfx[sound_id].numchannels == -1)
407 lp = -1; //denote the argument sound_id
409 for(i=0; i<snd_Channels; i++)
411 if(Channel[i].sound_id == sound_id && Channel[i].mo)
413 found++; //found one. Now, should we replace it??
414 if(priority >= Channel[i].priority)
415 { // if we're gonna kill one, then this'll be it
417 priority = Channel[i].priority;
421 if(found < S_sfx[sound_id].numchannels)
427 return(false); // don't replace any sounds
429 if(Channel[lp].handle)
431 if(I_SoundIsPlaying(Channel[lp].handle))
433 I_StopSound(Channel[lp].handle);
435 if(S_sfx[Channel[lp].sound_id].usefulness > 0)
437 S_sfx[Channel[lp].sound_id].usefulness--;
439 Channel[lp].mo = NULL;
444 //==========================================================================
448 //==========================================================================
450 void S_StopSound(mobj_t *origin)
454 for(i=0;i<snd_Channels;i++)
456 if(Channel[i].mo == origin)
458 I_StopSound(Channel[i].handle);
459 if(S_sfx[Channel[i].sound_id].usefulness > 0)
461 S_sfx[Channel[i].sound_id].usefulness--;
463 Channel[i].handle = 0;
464 Channel[i].mo = NULL;
473 //==========================================================================
477 //==========================================================================
479 void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
483 for(i=0;i<snd_Channels;i++)
485 if(Channel[i].mo == oldactor)
486 Channel[i].mo = newactor;
490 //==========================================================================
494 //==========================================================================
496 void S_PauseSound(void)
498 I_PauseSong(RegisteredSong);
501 //==========================================================================
505 //==========================================================================
507 void S_ResumeSound(void)
509 I_ResumeSong(RegisteredSong);
512 //==========================================================================
516 //==========================================================================
518 void S_UpdateSounds(mobj_t *listener)
527 listener = players[consoleplayer].mo;
528 if(snd_MaxVolume == 0)
533 if(NextCleanup < gametic)
535 for(i = 0; i < NUMSFX; i++)
537 if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
539 if(lumpcache[S_sfx[i].lumpnum])
541 if(((memblock_t *)((byte*) (lumpcache[S_sfx[i].lumpnum])-
542 sizeof(memblock_t)))->id == 0x1d4a11)
543 { // taken directly from the Z_ChangeTag macro
544 Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum],
548 S_sfx[i].usefulness = -1;
549 S_sfx[i].snd_ptr = NULL;
552 // Note, heretic does this every second (gametic+35)
553 NextCleanup = gametic+35*30; // every 30 seconds
555 for(i=0;i<snd_Channels;i++)
557 if(!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
561 if(!I_SoundIsPlaying(Channel[i].handle))
563 if(S_sfx[Channel[i].sound_id].usefulness > 0)
565 S_sfx[Channel[i].sound_id].usefulness--;
567 Channel[i].handle = 0;
568 Channel[i].mo = NULL;
569 Channel[i].sound_id = 0;
575 if(Channel[i].mo == NULL || Channel[i].sound_id == 0
576 || Channel[i].mo == listener)
582 absx = abs(Channel[i].mo->x-listener->x);
583 absy = abs(Channel[i].mo->y-listener->y);
584 dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
587 if(dist >= MAX_SND_DIST)
589 S_StopSound(Channel[i].mo);
596 vol = SoundCurve[dist];
597 angle = R_PointToAngle2(listener->x, listener->y,
598 Channel[i].mo->x, Channel[i].mo->y);
599 angle = (angle-viewangle)>>24;
605 I_UpdateSoundParams(Channel[i].handle, vol, sep, Channel[i].pitch);
606 priority = S_sfx[Channel[i].sound_id].priority;
607 priority *= PRIORITY_MAX_ADJUST-(dist/DIST_ADJUST);
608 Channel[i].priority = priority;
613 //==========================================================================
617 //==========================================================================
621 SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
627 I_SetChannels(snd_Channels);
628 I_SetMusicVolume(snd_MusicVolume);
629 S_SetMaxVolume(true);
632 //==========================================================================
636 //==========================================================================
638 void S_GetChannelInfo(SoundInfo_t *s)
643 s->channelCount = snd_Channels;
644 s->musicVolume = snd_MusicVolume;
645 s->soundVolume = snd_MaxVolume;
646 for(i = 0; i < snd_Channels; i++)
649 c->id = Channel[i].sound_id;
650 c->priority = Channel[i].priority;
651 c->name = S_sfx[c->id].name;
652 c->mo = Channel[i].mo;
653 c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)
658 void S_SetMaxVolume(boolean fullprocess)
664 SoundCurve[0] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE))*(snd_MaxVolume*8))>>7;
668 for(i = 0; i < MAX_SND_DIST; i++)
670 SoundCurve[i] = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+i)*(snd_MaxVolume*8))>>7;
675 //==========================================================================
679 //==========================================================================
681 void S_SetMusicVolume(void)
683 I_SetMusicVolume(snd_MusicVolume);
684 if(snd_MusicVolume == 0)
686 I_PauseSong(RegisteredSong);
692 I_ResumeSong(RegisteredSong);
696 //==========================================================================
700 //==========================================================================
702 void S_ShutDown(void)
707 I_StopSong(RegisteredSong);
708 I_UnRegisterSong(RegisteredSong);
713 //==================================================
718 boolean novideo; // if true, stay in text mode for debugging
721 //==========================================================================
724 static long _startSec;
726 void I_StartupTimer(void)
729 gettimeofday( &tv, 0 );
730 _startSec = tv.tv_sec;
733 //--------------------------------------------------------------------------
737 // Returns time in 1/35th second tics.
739 //--------------------------------------------------------------------------
744 gettimeofday( &tv, 0 );
746 //printf( "GT: %lx %lx\n", tv.tv_sec, tv.tv_usec );
748 // ticcount = ((tv.tv_sec * 1000000) + tv.tv_usec) / 28571;
749 ticcount = ((tv.tv_sec - _startSec) * 35) + (tv.tv_usec / 28571);
755 ============================================================================
759 ============================================================================
762 //==================================================
766 //==================================================
768 extern int usejoystick;
769 boolean joystickpresent;
770 unsigned joystickx, joysticky;
772 // returns false if not connected
773 boolean I_ReadJoystick (void)
779 int joyxl, joyxh, joyyl, joyyh;
781 boolean WaitJoyButton (void)
784 int oldbuttons, buttons;
790 buttons = ((inp(0x201) >> 4)&1)^1;
791 if (buttons != oldbuttons)
793 oldbuttons = buttons;
797 if ( (lastpress& 0x7f) == 1 )
799 joystickpresent = false;
807 buttons = ((inp(0x201) >> 4)&1)^1;
808 if (buttons != oldbuttons)
810 oldbuttons = buttons;
814 if ( (lastpress& 0x7f) == 1 )
816 joystickpresent = false;
835 int basejoyx, basejoyy;
837 void I_StartupJoystick (void)
839 int centerx, centery;
842 if ( M_CheckParm ("-nojoy") || !usejoystick )
845 if (!I_ReadJoystick ())
847 joystickpresent = false;
848 tprintf ("joystick not found\n ",1);
851 tprintf ("joystick found\n",1);
852 joystickpresent = true;
854 tprintf ("CENTER the joystick and press button 1:",1);
855 if (!WaitJoyButton ())
861 tprintf("\nPush the joystick to the UPPER LEFT corner and press button 1:",1);
862 if (!WaitJoyButton ())
865 joyxl = (centerx + joystickx)/2;
866 joyyl = (centerx + joysticky)/2;
868 tprintf("\nPush the joystick to the LOWER RIGHT corner and press button 1:",1);
869 if (!WaitJoyButton ())
872 joyxh = (centerx + joystickx)/2;
873 joyyh = (centery + joysticky)/2;
885 void I_JoystickEvents (void)
892 if (!joystickpresent)
896 ev.type = ev_joystick;
897 ev.data1 = 0; //((inp(0x201) >> 4)&15)^15;
899 if (joystickx < joyxl)
901 else if (joystickx > joyxh)
905 if (joysticky < joyyl)
907 else if (joysticky > joyyh)
924 void I_StartFrame (void)
931 ============================================================================
935 ============================================================================
938 void I_DivException (void);
939 int I_SetDivException (void);
944 ============================================================================
948 ============================================================================
957 = hook interrupts and set graphics mode
964 void I_StartupTimer(void);
966 novideo = M_CheckParm("novideo");
968 // tprintf("I_StartupJoystick ",1);
969 // I_StartupJoystick();
970 tprintf("S_Init... ",1);
983 = return to default system state
988 void I_ShutdownNet (void)
993 void I_Shutdown (void)
995 I_ShutdownGraphics ();
1009 void I_Error (char *error, ...)
1015 va_start (argptr,error);
1016 vprintf (error, argptr);
1022 //--------------------------------------------------------------------------
1026 // Shuts down net game, saves defaults, prints the exit text message,
1027 // goes to text mode, and exits.
1029 //--------------------------------------------------------------------------
1031 void put_dos2ansi (byte attrib)
1033 byte fore,back,blink=0,intens=0;
1034 int table[] = {30,34,32,36,31,35,33,37};
1036 fore = attrib&15; // bits 0-3
1037 back = attrib&112; // bits 4-6
1038 blink = attrib&128; // bit 7
1040 // Fix background, blink is either on or off.
1049 // Convert fore/back
1051 back = table[back] + 10;
1055 printf ("\033[%d;5;%dm\033[%dm", intens, fore, back);
1057 printf ("\033[%d;25;%dm\033[%dm", intens, fore, back);
1069 scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
1071 memcpy((void *)0xb8000, scr, 80*25*2);
1076 int386(0x10, (const union REGS *)®s, ®s); // Set text pos
1077 _settextposition(24, 1);
1079 for (i=0; i< 80*25*2; i+=2) {
1080 put_dos2ansi(scr[i+1]);
1083 // Cleanup after all that ANSI stuff
1098 byte *I_ZoneBase (int *size)
1101 int heap = 0x800000;
1103 ptr = malloc ( heap );
1106 I_Error (" Insufficient DPMI memory!");
1120 byte *I_AllocLow (int length)
1122 return malloc( length );
1126 ============================================================================
1130 ============================================================================
1140 #define DOOMCOM_ID 0x12345678l
1146 short intnum; // DOOM executes an int to execute commands
1148 // communication between DOOM and the driver
1149 short command; // CMD_SEND or CMD_GET
1150 short remotenode; // dest for send, set by get (-1 = no packet)
1151 short datalength; // bytes in doomdata to be sent
1153 // info common to all nodes
1154 short numnodes; // console is allways node 0
1155 short ticdup; // 1 = no duplication, 2-5 = dup for slow nets
1156 short extratics; // 1 = send a backup tic in every packet
1157 short deathmatch; // 1 = deathmatch
1158 short savegame; // -1 = new game, 0-5 = load savegame
1159 short episode; // 1-3
1163 // info specific to this node
1164 short consoleplayer;
1166 short angleoffset; // 1 = left, 0 = center, -1 = right
1167 short drone; // 1 = drone
1169 // packet data to be sent
1174 extern doomcom_t *doomcom;
1177 ====================
1181 ====================
1184 void I_InitNetwork (void)
1188 i = M_CheckParm ("-net");
1192 // single player game
1194 doomcom = malloc (sizeof (*doomcom) );
1195 memset (doomcom, 0, sizeof(*doomcom) );
1197 doomcom->id = DOOMCOM_ID;
1198 doomcom->numplayers = doomcom->numnodes = 1;
1199 doomcom->deathmatch = false;
1200 doomcom->consoleplayer = 0;
1201 doomcom->ticdup = 1;
1202 doomcom->extratics = 0;
1206 doomcom = (doomcom_t *)atoi(myargv[i+1]);
1208 doomcom->skill = startskill;
1209 doomcom->episode = startepisode;
1210 doomcom->map = startmap;
1211 doomcom->deathmatch = deathmatch;
1214 void I_NetCmd (void)
1217 I_Error ("I_NetCmd when not in netgame");
1220 //=========================================================================
1222 // I_CheckExternDriver
1224 // Checks to see if a vector, and an address for an external driver
1225 // have been passed.
1226 //=========================================================================
1228 void I_CheckExternDriver(void)
1232 if(!(i = M_CheckParm("-externdriver")))
1236 i_ExternData = (externdata_t *)atoi(myargv[i+1]);
1237 i_Vector = i_ExternData->vector;
1239 useexterndriver = true;
1243 int main( int argc, char** argv )
1251 fixed_t FixedMul (fixed_t a, fixed_t b)
1253 return ((long long) a * (long long) b) >> 16;
1256 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
1260 c = ((double)a) / ((double)b) * FRACUNIT;
1262 if (c >= 2147483648.0 || c < -2147483648.0)
1263 I_Error("FixedDiv: divide by zero");