summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/message.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/message.cc')
-rw-r--r--stone_soup/crawl-ref/source/message.cc640
1 files changed, 640 insertions, 0 deletions
diff --git a/stone_soup/crawl-ref/source/message.cc b/stone_soup/crawl-ref/source/message.cc
new file mode 100644
index 0000000000..353a069abc
--- /dev/null
+++ b/stone_soup/crawl-ref/source/message.cc
@@ -0,0 +1,640 @@
+/*
+ * File: message.cc
+ * Summary: Functions used to print messages.
+ * Written by: Linley Henzell
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+ *
+ * <3> 5/20/99 BWR Extended screen lines support
+ * <2> 5/08/99 JDJ mpr takes a const char* instead of a char array.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "message.h"
+#include "religion.h"
+
+#include <cstdarg>
+#include <cstring>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "initfile.h"
+#include "macro.h"
+#include "player.h"
+#include "stuff.h"
+#include "travel.h"
+#include "view.h"
+
+
+// circular buffer for keeping past messages
+message_item Store_Message[ NUM_STORED_MESSAGES ]; // buffer of old messages
+int Next_Message = 0; // end of messages
+
+char Message_Line = 0; // line of next (previous?) message
+
+static bool suppress_messages = false;
+
+no_messages::no_messages() : msuppressed(suppress_messages)
+{
+ suppress_messages = true;
+}
+
+no_messages::~no_messages()
+{
+ suppress_messages = msuppressed;
+}
+
+static char god_message_altar_colour( char god )
+{
+ int rnd;
+
+ switch (god)
+ {
+ case GOD_SHINING_ONE:
+ return (YELLOW);
+
+ case GOD_ZIN:
+ return (WHITE);
+
+ case GOD_ELYVILON:
+ return (LIGHTBLUE); // really, LIGHTGREY but that's plain text
+
+ case GOD_OKAWARU:
+ return (CYAN);
+
+ case GOD_YREDELEMNUL:
+ return (coinflip() ? DARKGREY : RED);
+
+ case GOD_KIKUBAAQUDGHA:
+ return (DARKGREY);
+
+ case GOD_XOM:
+ return (random2(15) + 1);
+
+ case GOD_VEHUMET:
+ rnd = random2(3);
+ return ((rnd == 0) ? LIGHTMAGENTA :
+ (rnd == 1) ? LIGHTRED
+ : LIGHTBLUE);
+
+ case GOD_MAKHLEB:
+ rnd = random2(3);
+ return ((rnd == 0) ? RED :
+ (rnd == 1) ? LIGHTRED
+ : YELLOW);
+
+ case GOD_TROG:
+ return (RED);
+
+ case GOD_NEMELEX_XOBEH:
+ return (LIGHTMAGENTA);
+
+ case GOD_SIF_MUNA:
+ return (BLUE);
+
+ case GOD_NO_GOD:
+ default:
+ return(YELLOW);
+ }
+}
+
+#ifdef USE_COLOUR_MESSAGES
+
+// returns a colour or MSGCOL_MUTED
+static char channel_to_colour( int channel, int param )
+{
+ char ret;
+
+ switch (Options.channels[ channel ])
+ {
+ case MSGCOL_PLAIN:
+ // note that if the plain channel is muted, then we're protecting
+ // the player from having that spead to other other channels here.
+ // The intent of plain is to give non-coloured messages, not to
+ // supress them.
+ if (Options.channels[ MSGCH_PLAIN ] >= MSGCOL_DEFAULT)
+ ret = LIGHTGREY;
+ else
+ ret = Options.channels[ MSGCH_PLAIN ];
+ break;
+
+ case MSGCOL_DEFAULT:
+ case MSGCOL_ALTERNATE:
+ switch (channel)
+ {
+ case MSGCH_GOD:
+ ret = (Options.channels[ channel ] == MSGCOL_DEFAULT)
+ ? god_colour( param )
+ : god_message_altar_colour( param );
+ break;
+
+ case MSGCH_DURATION:
+ ret = LIGHTBLUE;
+ break;
+
+ case MSGCH_DANGER:
+ ret = RED;
+ break;
+
+ case MSGCH_WARN:
+ ret = LIGHTRED;
+ break;
+
+ case MSGCH_FOOD:
+ ret = YELLOW;
+ break;
+
+ case MSGCH_INTRINSIC_GAIN:
+ ret = GREEN;
+ break;
+
+ case MSGCH_RECOVERY:
+ ret = LIGHTGREEN;
+ break;
+
+ case MSGCH_TALK:
+ ret = WHITE;
+ break;
+
+ case MSGCH_MONSTER_SPELL:
+ case MSGCH_MONSTER_ENCHANT:
+ ret = LIGHTMAGENTA;
+ break;
+
+ case MSGCH_MONSTER_DAMAGE:
+ ret = ((param == MDAM_DEAD) ? RED :
+ (param >= MDAM_HORRIBLY_DAMAGED) ? LIGHTRED :
+ (param >= MDAM_MODERATELY_DAMAGED) ? YELLOW
+ : LIGHTGREY);
+ break;
+
+ case MSGCH_PROMPT:
+ ret = CYAN;
+ break;
+
+ case MSGCH_DIAGNOSTICS:
+ ret = DARKGREY; // makes is easier to ignore at times -- bwr
+ break;
+
+ case MSGCH_PLAIN:
+ case MSGCH_ROTTEN_MEAT:
+ case MSGCH_EQUIPMENT:
+ default:
+ ret = param > 0? param : LIGHTGREY;
+ break;
+ }
+ break;
+
+ case MSGCOL_MUTED:
+ ret = MSGCOL_MUTED;
+ break;
+
+ default:
+ // Setting to a specific colour is handled here, special
+ // cases should be handled above.
+ if (channel == MSGCH_MONSTER_DAMAGE)
+ {
+ // a special case right now for monster damage (at least until
+ // the init system is improved)... selecting a specific
+ // colour here will result in only the death messages coloured
+ if (param == MDAM_DEAD)
+ ret = Options.channels[ channel ];
+ else if (Options.channels[ MSGCH_PLAIN ] >= MSGCOL_DEFAULT)
+ ret = LIGHTGREY;
+ else
+ ret = Options.channels[ MSGCH_PLAIN ];
+ }
+ else
+ ret = Options.channels[ channel ];
+ break;
+ }
+
+ return (ret);
+}
+
+#else // don't use colour messages
+
+static char channel_to_colour( int channel, int param )
+{
+ return (LIGHTGREY);
+}
+
+#endif
+
+static void do_message_print( int channel, int param,
+ const char *format, va_list argp )
+{
+ char buff[80];
+ vsnprintf( buff, sizeof( buff ), format, argp );
+ buff[79] = '\0';
+
+ mpr(buff, channel, param);
+}
+
+void mprf( int channel, const char *format, ... )
+{
+ va_list argp;
+ va_start( argp, format );
+ do_message_print( channel, 0, format, argp );
+ va_end( argp );
+}
+
+void mprf( const char *format, ... )
+{
+ va_list argp;
+ va_start( argp, format );
+ do_message_print( MSGCH_PLAIN, 0, format, argp );
+ va_end( argp );
+}
+
+void mpr(const char *inf, int channel, int param)
+{
+ if (suppress_messages)
+ return;
+
+ char info2[80];
+
+ int colour = channel_to_colour( channel, param );
+ if (colour == MSGCOL_MUTED)
+ return;
+
+ interrupt_activity( AI_MESSAGE, channel_to_str(channel) + ":" + inf );
+
+ // If you're travelling, only certain user-specified messages can break
+ // travel
+ if (you.running < 0)
+ {
+ std::string message = inf;
+ for (unsigned i = 0; i < Options.stop_travel.size(); ++i)
+ {
+ if (Options.stop_travel[i].is_filtered( channel, message ))
+ {
+ stop_running();
+ break;
+ }
+ }
+ }
+
+ if (Options.sound_mappings.size() > 0)
+ {
+ std::string message = inf;
+ for (unsigned i = 0; i < Options.sound_mappings.size(); i++)
+ {
+ // Maybe we should allow message channel matching as for
+ // stop_travel?
+ if (Options.sound_mappings[i].pattern.matches(message))
+ {
+ play_sound(Options.sound_mappings[i].soundfile.c_str());
+ break;
+ }
+ }
+ }
+
+ flush_input_buffer( FLUSH_ON_MESSAGE );
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ textcolor(LIGHTGREY);
+
+ const int num_lines = get_number_of_lines();
+
+ if (Message_Line == num_lines - 18) // ( Message_Line == 8 )
+ more();
+
+ gotoxy( (Options.delay_message_clear) ? 2 : 1, Message_Line + 18 );
+ strncpy(info2, inf, 78);
+ info2[78] = 0;
+
+ textcolor( colour );
+ cprintf(info2);
+ //
+ // reset colour
+ textcolor(LIGHTGREY);
+
+ Message_Line++;
+
+ if (Options.delay_message_clear
+ && channel != MSGCH_PROMPT
+ && Message_Line == num_lines - 18)
+ {
+ more();
+ }
+
+ // equipment lists just waste space in the message recall
+ if (channel != MSGCH_EQUIPMENT)
+ {
+ /* Put the message into Store_Message, and move the '---' line forward */
+ Store_Message[ Next_Message ].text = inf;
+ Store_Message[ Next_Message ].channel = channel;
+ Store_Message[ Next_Message ].param = param;
+ Next_Message++;
+
+ if (Next_Message >= NUM_STORED_MESSAGES)
+ Next_Message = 0;
+ }
+} // end mpr()
+
+bool any_messages(void)
+{
+ return (Message_Line > 0);
+}
+
+void mesclr( bool force )
+{
+ // if no messages, return.
+ if (!any_messages())
+ return;
+
+ if (!force && Options.delay_message_clear)
+ {
+ gotoxy( 1, Message_Line + 18 );
+ textcolor( channel_to_colour( MSGCH_PLAIN, 0 ) );
+ cprintf( ">" );
+ return;
+ }
+
+ // turn cursor off -- avoid 'cursor dance'
+ _setcursortype(_NOCURSOR);
+
+#ifdef DOS_TERM
+ window(1, 18, 78, 25);
+ clrscr();
+ window(1, 1, 80, 25);
+#endif
+
+#ifdef PLAIN_TERM
+ int startLine = 18;
+
+ gotoxy(1, startLine);
+
+#ifdef UNIX
+ clear_to_end_of_screen();
+#else
+
+ int numLines = get_number_of_lines() - startLine + 1;
+
+ char blankline[81];
+ memset(blankline, ' ', sizeof blankline);
+ blankline[80] = 0;
+
+ for (int i = 0; i < numLines; i++)
+ {
+ cprintf( blankline );
+
+ if (i < numLines - 1)
+ {
+ cprintf(EOL);
+ }
+ }
+#endif
+#endif
+
+ // turn cursor back on
+ _setcursortype(_NORMALCURSOR);
+
+ Message_Line = 0;
+} // end mseclr()
+
+void more(void)
+{
+ char keypress = 0;
+
+#ifdef PLAIN_TERM
+ gotoxy( 2, get_number_of_lines() );
+#endif
+
+#ifdef DOS_TERM
+ window(1, 18, 80, 25);
+ gotoxy(2, 7);
+#endif
+
+ textcolor(LIGHTGREY);
+
+#ifdef DOS
+ cprintf(EOL);
+#endif
+ cprintf("--more--");
+
+ do
+ {
+ keypress = getch();
+ }
+ while (keypress != ' ' && keypress != '\r' && keypress != '\n');
+
+ mesclr( (Message_Line >= get_number_of_lines() - 18) );
+} // end more()
+
+std::string get_last_messages(int mcount)
+{
+ if (mcount <= 0) return std::string();
+ if (mcount > NUM_STORED_MESSAGES) mcount = NUM_STORED_MESSAGES;
+
+ bool full_buffer = Store_Message[ NUM_STORED_MESSAGES - 1 ].text.length() == 0;
+ int initial = Next_Message - mcount;
+ if (initial < 0 || initial > NUM_STORED_MESSAGES)
+ initial = full_buffer? initial + NUM_STORED_MESSAGES : 0;
+
+ std::string text;
+ int count = 0;
+ for (int i = initial; i != Next_Message; )
+ {
+ if (Store_Message[i].text.length())
+ {
+ text += Store_Message[i].text;
+ text += EOL;
+ count++;
+ }
+
+ if (++i >= NUM_STORED_MESSAGES)
+ i -= NUM_STORED_MESSAGES;
+ }
+
+ // An extra line of clearance.
+ if (count) text += EOL;
+
+ return text;
+}
+
+void replay_messages(void)
+{
+ int win_start_line = 0;
+ unsigned char keyin;
+
+ bool full_buffer = true;
+ int num_msgs = NUM_STORED_MESSAGES;
+ int first_message = Next_Message;
+
+ const int num_lines = get_number_of_lines();
+
+ if (Store_Message[ NUM_STORED_MESSAGES - 1 ].text.length() == 0)
+ {
+ full_buffer = false;
+ first_message = 0;
+ num_msgs = Next_Message;
+ }
+
+ int last_message = Next_Message - 1;
+ if (last_message < 0)
+ last_message += NUM_STORED_MESSAGES;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ // track back a screen's worth of messages from the end
+ win_start_line = Next_Message - (num_lines - 2);
+ if (win_start_line < 0)
+ {
+ if (full_buffer)
+ win_start_line += NUM_STORED_MESSAGES;
+ else
+ win_start_line = 0;
+ }
+
+ for(;;)
+ {
+ // turn cursor off
+ _setcursortype(_NOCURSOR);
+
+ clrscr();
+
+ gotoxy(1, 1);
+
+ for (int i = 0; i < num_lines - 2; i++)
+ {
+ // calculate line in circular buffer
+ int line = win_start_line + i;
+ if (line >= NUM_STORED_MESSAGES)
+ line -= NUM_STORED_MESSAGES;
+
+ // avoid wrap-around
+ if (line == first_message && i != 0)
+ break;
+
+ int colour = channel_to_colour( Store_Message[ line ].channel,
+ Store_Message[ line ].param );
+ if (colour == MSGCOL_MUTED)
+ continue;
+
+ textcolor( colour );
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( "%d: %s", line, Store_Message[ line ].text.c_str() );
+#else
+ cprintf( Store_Message[ line ].text.c_str() );
+#endif
+
+ cprintf(EOL);
+ textcolor(LIGHTGREY);
+ }
+
+ // print a footer -- note: relative co-ordinates start at 1
+ int rel_start;
+ if (!full_buffer)
+ {
+ if (Next_Message == 0) // no messages!
+ rel_start = 0;
+ else
+ rel_start = win_start_line + 1;
+ }
+ else if (win_start_line >= first_message)
+ rel_start = win_start_line - first_message + 1;
+ else
+ rel_start = (win_start_line + NUM_STORED_MESSAGES) - first_message + 1;
+
+ int rel_end = rel_start + (num_lines - 2) - 1;
+ if (rel_end > num_msgs)
+ rel_end = num_msgs;
+
+ cprintf( "-------------------------------------------------------------------------------" );
+ cprintf(EOL);
+ cprintf( "<< Lines %d-%d of %d >>", rel_start, rel_end, num_msgs );
+
+ // turn cursor back on
+ _setcursortype(_NORMALCURSOR);
+
+ keyin = get_ch();
+
+ if ((full_buffer && NUM_STORED_MESSAGES > num_lines - 2)
+ || (!full_buffer && Next_Message > num_lines - 2))
+ {
+ int new_line;
+ int end_mark;
+
+ if (keyin == 'k' || keyin == '8' || keyin == '-')
+ {
+ new_line = win_start_line - (num_lines - 2);
+
+ // end_mark is equivalent to Next_Message, but
+ // is always less than win_start_line.
+ end_mark = first_message;
+ if (end_mark > win_start_line)
+ end_mark -= NUM_STORED_MESSAGES;
+
+ ASSERT( end_mark <= win_start_line );
+
+ if (new_line <= end_mark)
+ new_line = end_mark; // hit top
+
+ // handle wrap-around
+ if (new_line < 0)
+ {
+ if (full_buffer)
+ new_line += NUM_STORED_MESSAGES;
+ else
+ new_line = 0;
+ }
+ }
+ else if (keyin == 'j' || keyin == '2' || keyin == '+')
+ {
+ new_line = win_start_line + (num_lines - 2);
+
+ // as above, but since we're adding we want
+ // this mark to always be greater.
+ end_mark = last_message;
+ if (end_mark < win_start_line)
+ end_mark += NUM_STORED_MESSAGES;
+
+ ASSERT( end_mark >= win_start_line );
+
+ // hit bottom
+ if (new_line >= end_mark - (num_lines - 2))
+ new_line = end_mark - (num_lines - 2) + 1;
+
+ if (new_line >= NUM_STORED_MESSAGES)
+ new_line -= NUM_STORED_MESSAGES;
+ }
+ else
+ break;
+
+ win_start_line = new_line;
+ }
+ else
+ {
+ if (keyin != 'k' && keyin != '8' && keyin != '-'
+ && keyin != 'j' && keyin != '2' && keyin != '+')
+ {
+ break;
+ }
+ }
+ }
+
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return;
+} // end replay_messages()