1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #include "rt_def.h"
21 #include "rt_view.h"
22 #include "z_zone.h"
23 #include "w_wad.h"
24 #include "lumpy.h"
25 #include "rt_util.h"
26 #include "rt_vid.h"
27 #include "rt_str.h"
28 #include "rt_menu.h"
29 #include "_rt_msg.h"
30 #include "rt_msg.h"
31 #include "rt_playr.h"
32 #include "isr.h"
33 #include "rt_main.h"
34 #include "rt_net.h"
35 #include "rt_com.h"
36 
37 #ifdef DOS
38 #include <mem.h>
39 #endif
40 
41 #include <stdlib.h>
42 //MED
43 #include "memcheck.h"
44 
45 
46 /*
47 =============================================================================
48 
49                                GLOBALS
50 
51 =============================================================================
52 */
53 messagetype Messages[MAXMSGS];
54 
55 /*
56 =============================================================================
57 
58                                LOCAL
59 
60 =============================================================================
61 */
62 
63 static int  UpdateMessageBackground;
64 static int  MessageSystemStarted=0;
65 static int  LastMessageTime;
66 static boolean EraseMessage[ MAXMSGS ];
67 static int     MessageOrder[ MAXMSGS ];
68 static int     TotalMessages = 0;
69 static int     MsgPos = 0;
70 
71 boolean MessagesEnabled = true;
72 
StringLength(char * string)73 int StringLength (char *string)
74 {
75 	int length=0;
76 
77    while ((*string)!=0)
78       {
79       length++;
80       string++;
81       }
82 
83    length++;
84 
85    return length;
86 }
87 
88 /*
89 ====================
90 =
91 = ResetMessageTime
92 =
93 ====================
94 */
95 
ResetMessageTime(void)96 void ResetMessageTime ( void )
97 {
98    LastMessageTime=GetTicCount();
99 }
100 
101 /*
102 ====================
103 =
104 = InitializeMessages
105 =
106 ====================
107 */
InitializeMessages(void)108 void InitializeMessages
109    (
110    void
111    )
112 
113    {
114    int i;
115    boolean start;
116 
117    start = false;
118 
119    if ( MessageSystemStarted == 0 )
120       {
121       start = true;
122       MessageSystemStarted = 1;
123       memset( Messages, 0, sizeof( Messages ) );
124       }
125 
126    for ( i = 0; i < MAXMSGS; i++ )
127       {
128       if ( Messages[ i ].active == 1 )
129          {
130          SafeFree( Messages[ i ].text );
131          Messages[ i ].active  = 0;
132          Messages[ i ].tictime = 0;
133          Messages[ i ].flags   = 0;
134          Messages[ i ].text    = NULL;
135          }
136       }
137 
138    MSG.messageon = false;
139 
140    LastMessageTime = 0;
141    UpdateMessageBackground = 0;
142    TotalMessages = 0;
143    memset( EraseMessage,  0, sizeof( EraseMessage ) );
144    memset( MessageOrder, -1, sizeof( MessageOrder ) );
145 
146    // Only print startup message if it's the first time in
147    if ( start && !quiet )
148       {
149       printf( "RT_MSG: Message System Started\n" );
150       }
151    }
152 
153 
154 /*
155 ====================
156 =
157 = GetMessageOrder
158 =
159 ====================
160 */
GetMessageOrder(void)161 void GetMessageOrder
162    (
163    void
164    )
165 
166    {
167    int  i;
168    int  lowest;
169    int  lowesttime;
170    byte done[ MAXMSGS ];
171    boolean found;
172 
173    memset( &done[ 0 ],    0, sizeof( done ) );
174    memset( MessageOrder, -1, sizeof( MessageOrder ) );
175 
176    for( TotalMessages = 0; TotalMessages < MAXMSGS; TotalMessages++ )
177       {
178       found = false;
179       lowesttime = 1000;
180       lowest = 0;
181 
182       for( i = 0; i < MAXMSGS; i++ )
183          {
184          if ( ( Messages[ i ].active == 1 ) && ( done[ i ] == 0 ) &&
185             ( Messages[ i ].tictime < lowesttime ) )
186             {
187             lowesttime = Messages[ i ].tictime;
188             lowest = i;
189             found = true;
190             }
191          }
192 
193       if ( !found )
194          {
195          break;
196          }
197 
198       done[ lowest ] = 1;
199       MessageOrder[ TotalMessages ] = lowest;
200       }
201    }
202 
203 
204 /*
205 ====================
206 =
207 = DeleteMessage
208 =
209 ====================
210 */
DeleteMessage(int num)211 void DeleteMessage
212    (
213    int num
214    )
215 
216    {
217    int i;
218    int msg;
219    boolean found;
220 
221    found = false;
222    for( i = 0; i < TotalMessages; i++ )
223       {
224       msg = MessageOrder[ i ];
225 
226       if ( msg == num )
227          {
228          found = true;
229          }
230 
231       if ( found )
232          {
233          UpdateMessageBackground -= EraseMessage[ i ];
234          UpdateMessageBackground += 3;
235          EraseMessage[ i ] = 3;
236          }
237       }
238 
239    SafeFree( Messages[ num ].text );
240    memset( &Messages[ num ], 0, sizeof( messagetype ) );
241 
242    GetMessageOrder();
243    }
244 
245 
246 /*
247 ====================
248 =
249 = DeletePriorityMessage
250 =
251 ====================
252 */
DeletePriorityMessage(int flags)253 void DeletePriorityMessage ( int flags )
254 {
255    int i;
256 
257    for (i=0;i<MAXMSGS;i++)
258       {
259       if (Messages[i].active==1)
260          {
261          if (Messages[i].flags==flags)
262             DeleteMessage(i);
263          }
264       }
265 }
266 
267 
268 /*
269 ====================
270 =
271 = GetFreeMessage
272 =
273 ====================
274 */
GetFreeMessage(void)275 int GetFreeMessage
276    (
277    void
278    )
279 
280    {
281    int i;
282    int found;
283 
284    for( i = 0; i < MAXMSGS; i++ )
285       {
286       if ( Messages[ i ].active == 0 )
287          {
288          return( i );
289          }
290       }
291 
292    found = -1;
293 
294    for( i = 0; i < MAXMSGS; i++ )
295       {
296       if ( Messages[ i ].tictime >= 0 )
297          {
298          if ( found == -1 )
299             {
300             found = i;
301             }
302          else
303             {
304             if ( Messages[ i ].tictime < Messages[ found ].tictime )
305                {
306                found = i;
307                }
308             }
309          }
310       }
311 
312    DeleteMessage( found );
313 
314    return( found );
315    }
316 
317 
318 /*
319 ====================
320 =
321 = SetMessage
322 =
323 ====================
324 */
SetMessage(int num,char * text,int flags)325 void SetMessage
326    (
327    int   num,
328    char *text,
329    int   flags
330    )
331 
332    {
333    int i;
334    int msg;
335    int length;
336    boolean found;
337 
338 
339    length = StringLength( text );
340 
341    Messages[ num ].active = 1;
342    Messages[ num ].flags  = flags;
343 
344    if ( PERMANENT_MSG( flags ) )
345       {
346       int l;
347 
348       l = COM_MAXTEXTSTRINGLENGTH + 1;
349       Messages[ num ].text = SafeMalloc( l );
350       memset( Messages[ num ].text, 0, l );
351 
352       // Hack so that we can place menu in certain order
353       Messages[ num ].tictime = -100 + MsgPos;
354       }
355    else
356       {
357       Messages[ num ].text = SafeMalloc( length );
358 
359       memset( Messages[ num ].text, 0, length );
360       Messages[ num ].tictime = MESSAGETIME;
361       }
362 
363    memcpy( Messages[ num ].text, text, length );
364 
365    GetMessageOrder();
366    found = false;
367    for( i = 0; i < TotalMessages; i++ )
368       {
369       msg = MessageOrder[ i ];
370       if ( msg == num )
371          {
372          found = true;
373          }
374       else if ( found )
375          {
376          UpdateMessageBackground -= EraseMessage[ i - 1 ];
377          UpdateMessageBackground += 3;
378          EraseMessage[ i - 1 ] = 3;
379          }
380       }
381    }
382 
383 
384 /*
385 ====================
386 =
387 = AddMessage
388 =
389 ====================
390 */
AddMessage(char * text,int flags)391 int AddMessage
392    (
393    char *text,
394    int flags
395    )
396 
397    {
398    int new;
399 
400    if ( MessageSystemStarted == 0 )
401       {
402       Error( "Called AddMessage without starting Message system\n" );
403       }
404 
405    if ( !( flags & MSG_NODELETE ) )
406       {
407       DeletePriorityMessage( flags );
408       }
409 
410    new = GetFreeMessage();
411    SetMessage( new, text, flags );
412 
413    return( new );
414    }
415 
416 /*
417 ====================
418 =
419 = UpdateMessages
420 =
421 ====================
422 */
UpdateMessages(void)423 void UpdateMessages
424    (
425    void
426    )
427 
428    {
429    int messagetics;
430    int i;
431 
432    messagetics = GetTicCount() - LastMessageTime;
433    LastMessageTime = GetTicCount();
434 
435    if ( GamePaused == true )
436       {
437       return;
438       }
439 
440    for( i = 0; i < MAXMSGS; i++ )
441       {
442       if ( ( Messages[ i ].active == 1 ) &&
443          ( !PERMANENT_MSG( Messages[ i ].flags ) ) )
444          {
445          Messages[ i ].tictime -= messagetics;
446          if ( Messages[ i ].tictime <= 0 )
447             {
448             DeleteMessage( i );
449             }
450          }
451       }
452    }
453 
454 
455 /*
456 ====================
457 =
458 = DisplayMessage
459 =
460 ====================
461 */
462 
DisplayMessage(int num,int position)463 void DisplayMessage
464    (
465    int num,
466    int position
467    )
468 
469    {
470    PrintX = 1;
471    PrintY = 2 + ( position * 9 );
472 
473    if ( SHOW_TOP_STATUS_BAR() )
474       {
475       PrintY += 16;
476       }
477    if ( !MessagesEnabled )
478       {
479       switch ( Messages[ num ].flags )
480          {
481          case MSG_QUIT:
482          case MSG_MACRO:
483          case MSG_MODEM:
484          case MSG_NAMEMENU:
485          case MSG_MSGSYSTEM:
486             break;
487 
488          case MSG_REMOTERIDICULE:
489          case MSG_REMOTE:
490          case MSG_GAME:
491          case MSG_DOOR:
492          case MSG_BONUS:
493          case MSG_BONUS1:
494          case MSG_CHEAT:
495          case MSG_SYSTEM:
496          default :
497             DeleteMessage( num );
498             return;
499          }
500       }
501 
502    switch ( Messages[ num ].flags )
503       {
504       case MSG_REMOTERIDICULE:
505       case MSG_REMOTE:
506          fontcolor = egacolor[ WHITE ];
507          break;
508 
509       case MSG_MODEM:
510          fontcolor = egacolor[ LIGHTBLUE ];
511          DrawIString( PrintX, PrintY, "Message>", Messages[ num ].flags );
512          PrintX += 8 * 8;
513          fontcolor = egacolor[ LIGHTGRAY ];
514          break;
515 
516       case MSG_GAME:
517       case MSG_DOOR:
518       case MSG_BONUS:
519       case MSG_BONUS1:
520       case MSG_NAMEMENU:
521          fontcolor = egacolor[ GREEN ];
522          break;
523 
524       case MSG_CHEAT:
525          fontcolor = egacolor[ YELLOW ];
526          break;
527       case MSG_MSGSYSTEM:
528       case MSG_SYSTEM:
529       case MSG_QUIT:
530       case MSG_MACRO:
531          fontcolor = egacolor[ RED ];
532          break;
533 
534       default :
535 #if ((DEVELOPMENT == 1))
536          Error( "DisplayMessage called with invalid priority number." );
537 #else
538          fontcolor = egacolor[ LIGHTGREEN ];
539 #endif
540       }
541 
542    DrawIString( PrintX, PrintY, Messages[ num ].text, Messages[ num ].flags );
543    }
544 
545 
546 
547 /*
548 ====================
549 =
550 = RestoreMessageBackground
551 =
552 ====================
553 */
RestoreMessageBackground(void)554 void RestoreMessageBackground
555    (
556    void
557    )
558 
559    {
560    pic_t *shape;
561    int i;
562    int y;
563 
564    if ( UpdateMessageBackground > 0 )
565       {
566       y = 18;
567       for( i = 0; i < MAXMSGS; i++ )
568          {
569          if ( EraseMessage[ i ] )
570             {
571             UpdateMessageBackground--;
572             EraseMessage[ i ]--;
573             if ( viewsize < 15 )
574                {
575                shape = W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
576                DrawTiledRegion( 0, y, 320, 9, 0, y, shape );
577                }
578             if ( viewsize == 0 )
579                {
580                if ( ( y + 9 > YOURCPUSUCKS_Y ) &&
581                   ( y < ( YOURCPUSUCKS_Y + YOURCPUSUCKS_HEIGHT ) ) )
582                   {
583                   DrawCPUJape();
584                   }
585                }
586             }
587 
588          y += 9;
589          }
590       }
591    }
592 
593 
594 /*
595 ====================
596 =
597 = DrawMessages
598 =
599 ====================
600 */
DrawMessages(void)601 void DrawMessages
602    (
603    void
604    )
605 
606    {
607    int i;
608 
609    if ( TotalMessages > 0 )
610       {
611       IFont = ( cfont_t * )W_CacheLumpName( "ifnt", PU_CACHE, Cvt_cfont_t, 1 );
612 
613       for( i = 0; i < TotalMessages; i++ )
614          {
615          DisplayMessage( MessageOrder[ i ], i );
616          }
617       }
618    UpdateMessages();
619    }
620 
621 
622 /*
623 ====================
624 =
625 = UpdateModemMessage
626 =
627 ====================
628 */
UpdateModemMessage(int num,char c)629 void UpdateModemMessage
630    (
631    int num,
632    char c
633    )
634 
635    {
636    int i;
637 
638    Messages[ num ].text[ MSG.length - 1 ] = ( byte )c;
639    Messages[ num ].text[ MSG.length ]     = ( byte )'_';
640    MSG.length++;
641 
642    for( i = 0; i < TotalMessages; i++ )
643       {
644       if ( MessageOrder[ i ] == num )
645          {
646          UpdateMessageBackground -= EraseMessage[ i ];
647          UpdateMessageBackground += 3;
648          EraseMessage[ i ] = 3;
649          break;
650          }
651       }
652    }
653 
654 
655 /*
656 ====================
657 =
658 = ModemMessageDeleteChar
659 =
660 ====================
661 */
ModemMessageDeleteChar(int num)662 void ModemMessageDeleteChar
663    (
664    int num
665    )
666 
667    {
668    int i;
669 
670    MSG.length--;
671    Messages[ num ].text[ MSG.length ]     = ( byte )0;
672    Messages[ num ].text[ MSG.length - 1 ] = ( byte )'_';
673 
674    for( i = 0; i < TotalMessages; i++ )
675       {
676       if ( MessageOrder[ i ] == num )
677          {
678          UpdateMessageBackground -= EraseMessage[ i ];
679          UpdateMessageBackground += 3;
680          EraseMessage[ i ] = 3;
681          break;
682          }
683       }
684    }
685 
686 
687 /*
688 ====================
689 =
690 = DrawPlayerSelectionMenu
691 =
692 ====================
693 */
694 
DrawPlayerSelectionMenu(void)695 void DrawPlayerSelectionMenu
696    (
697    void
698    )
699 
700    {
701    int i;
702    int p;
703    char str[ 20 ];
704 
705    p = 1;
706    MsgPos = 1;
707    AddMessage( "Press a key from 0 to 9 to select", MSG_NAMEMENU );
708    MsgPos++;
709    AddMessage( "who to send your message to:", MSG_NAMEMENU );
710    MsgPos++;
711 
712    for( i = 0; i < numplayers; i++ )
713       {
714       if ( i != consoleplayer )
715          {
716          strcpy( str, "0 - " );
717          strcat( str, PLAYERSTATE[ i ].codename );
718          str[ 0 ] = '0' + p;
719          p++;
720          if ( p > 9 )
721             {
722             p = 0;
723             }
724 
725          AddMessage( str, MSG_NAMEMENU );
726          MsgPos++;
727          }
728       }
729 
730    if ( ( MsgPos < MAXMSGS - 1 ) && ( gamestate.teamplay ) )
731       {
732       AddMessage( "T - All team members", MSG_NAMEMENU );
733       MsgPos++;
734       }
735 
736    if ( MsgPos < MAXMSGS - 1 )
737       {
738       AddMessage( "A - All players", MSG_NAMEMENU );
739       }
740 
741    MsgPos = 0;
742    }
743 
744 
745 /*
746 ====================
747 =
748 = FinishModemMessage
749 =
750 ====================
751 */
FinishModemMessage(int num,boolean send)752 void FinishModemMessage
753    (
754    int num,
755    boolean send
756    )
757    {
758    if ( ( !MSG.inmenu ) && ( MSG.length > 0 ) )
759       {
760       Messages[ num ].text[ MSG.length - 1 ] = ( byte )0;
761       MSG.length--;
762       }
763 
764    if ( ( send == true ) && ( ( MSG.length > 0 ) ||
765       ( MSG.remoteridicule != -1 ) ) )
766       {
767       if ( ( MSG.directed ) && ( !MSG.inmenu ) )
768          {
769          DrawPlayerSelectionMenu();
770          MSG.messageon = true;
771          MSG.inmenu = true;
772          return;
773          }
774 
775       MSG.messageon = false;
776       if ( MSG.remoteridicule != -1 )
777          {
778          AddRemoteRidiculeCommand( consoleplayer, MSG.towho,
779             MSG.remoteridicule );
780          }
781       if ( MSG.length > 0 )
782          {
783          AddTextMessage( Messages[ num ].text, MSG.length, MSG.towho );
784          }
785       }
786 
787    if ( MSG.inmenu )
788       {
789       DeletePriorityMessage( MSG_NAMEMENU );
790       }
791 
792    DeleteMessage( num );
793    }
794