Subversion Repositories Games.Chess Giants

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // interlocutor.cpp
  2.  
  3. #include "common.h"
  4.  
  5.  
  6. // global variables used in this module only
  7. static const wchar_t rtf_header[] = L"{\\rtf1\\ansi"
  8.                                        L"{\\fonttbl\\f0\\f{Comic Sans MS};}"
  9.                                        L"{\\colortbl;\\red0\\green0\\blue0;\\red192\\green192\\blue192;\\red0\\green0\\blue100;\\red160\\green160\\blue160;}"
  10.                                        L"\\f0\\fs18\\cf3\\pard\n"
  11.                                     L"}\n";
  12. static wchar_t text_buffer[1024 * 1024];
  13.  
  14.  
  15. void Interlocutors_Init (void)
  16. {
  17.    // this function resets the interlocutors array, preparing it for a new use
  18.  
  19.    interlocutors = NULL; // reset the array pointer
  20.    interlocutor_count = 0; // and set the element count to zero
  21.  
  22.    return; // that's all there is
  23. }
  24.  
  25.  
  26. void Interlocutors_Shutdown (void)
  27. {
  28.    // this function empties the interlocutors array, closing windows and freeing allocated resources
  29.  
  30.    int interlocutor_index;
  31.  
  32.    // for each player card we know...
  33.    for (interlocutor_index = 0; interlocutor_index < interlocutor_count; interlocutor_index++)
  34.    {
  35.       if (IsWindow (interlocutors[interlocutor_index].hWnd))
  36.          DestroyWindow (interlocutors[interlocutor_index].hWnd); // destroy any eventual opened chat window
  37.       SAFE_free ((void **) &interlocutors[interlocutor_index].dialogtext); // free the interlocutor's dialog text buffer
  38.       interlocutors[interlocutor_index].dialogtext_size = 0; // and reset this buffer's size
  39.    }
  40.    SAFE_free ((void **) &interlocutors); // free the chat interlocutors array
  41.    interlocutor_count = 0; // and reset the interlocutors count
  42.  
  43.    return; // finished
  44. }
  45.  
  46.  
  47. interlocutor_t *Interlocutor_FindOrCreate (const wchar_t *nickname)
  48. {
  49.    // this function returns a pointer to the interlocutor whose nickname is specified,
  50.    // creating a new slot for him in the interlocutors array if he can't be found.
  51.  
  52.    interlocutor_t *interlocutor;
  53.    int interlocutor_index;
  54.  
  55.    // see if we already know this interlocutor, loop through all of them...
  56.    for (interlocutor_index = 0; interlocutor_index < interlocutor_count; interlocutor_index++)
  57.       if (_wcsicmp (nickname, interlocutors[interlocutor_index].nickname) == 0)
  58.          break; // break as soon as we find it
  59.  
  60.    // have we found it ?
  61.    if (interlocutor_index < interlocutor_count)
  62.    {
  63.       // get a quick access to interlocutor
  64.       interlocutor = &interlocutors[interlocutor_index];
  65.  
  66.       // is this interlocutor NO LONGER active ?
  67.       if (!interlocutor->is_active)
  68.       {
  69.          interlocutor->hWnd = NULL; // reset some values for this interlocutor
  70.          interlocutor->current_displaypicture = 0;
  71.          interlocutor->is_active = true; // remember it's becoming active again
  72.  
  73.          Window_Chat (interlocutor_index); // his chat window has been closen, so fire it up again
  74.       }
  75.       else
  76.       {
  77.          // does the chat window exist AND is it currently NOT the foreground window ?
  78.          if (IsWindow (interlocutor->hWnd) && (GetForegroundWindow () != interlocutor->hWnd))
  79.          {
  80.             interlocutor->update_dialog = true; // update this interlocutor's window
  81.             ShowWindow (interlocutor->hWnd, SW_RESTORE); // restore it from the taskbar
  82.             SetForegroundWindow (interlocutor->hWnd); // bring the window to front if necessary
  83.          }
  84.       }
  85.    }
  86.  
  87.    // else we haven't found it
  88.    else
  89.    {
  90.       // so resize our interlocutors array and add this interlocutor to it
  91.       interlocutors = (interlocutor_t *) SAFE_realloc (interlocutors, interlocutor_count, interlocutor_count + 1, sizeof (interlocutor_t), false);
  92.       interlocutor_count++; // we know now one interlocutor more
  93.  
  94.       // get a quick access to interlocutor. Only do it after the realloc, as the array may have moved.
  95.       interlocutor = &interlocutors[interlocutor_index];
  96.  
  97.       // reset some values for this new interlocutor
  98.       wcscpy_s (interlocutor->nickname, WCHAR_SIZEOF (interlocutor->nickname), nickname); // save nickname
  99.       interlocutor->hWnd = NULL;
  100.       interlocutor->dialogtext = NULL; // no dialog text yet
  101.       interlocutor->dialogtext_size = 0;
  102.       interlocutor->current_displaypicture = 0;
  103.       interlocutor->is_active = true;
  104.  
  105.       // and fire up the new chat window
  106.       Window_Chat (interlocutor_index);
  107.    }
  108.  
  109.    return (interlocutor); // return pointer to interlocutor
  110. }
  111.  
  112.  
  113. interlocutor_t *Interlocutor_FindByWindowHandle (HWND window_handle)
  114. {
  115.    // this function returns a pointer to the interlocutor whose chat window handle
  116.    // matches the one specified. If no such chat window exists, NULL is returned.
  117.  
  118.    int interlocutor_index;
  119.  
  120.    // cycle through all interlocutors and find the one we want...
  121.    for (interlocutor_index = 0; interlocutor_index < interlocutor_count; interlocutor_index++)
  122.       if (interlocutors[interlocutor_index].hWnd == window_handle)
  123.          return (&interlocutors[interlocutor_index]); // found it, return its pointer
  124.  
  125.    return (NULL); // we couldn't find that interlocutor, return FALSE
  126. }
  127.  
  128.  
  129. void Interlocutor_Chat (interlocutor_t *interlocutor, const wchar_t *sender, bool is_localsender, const wchar_t *fmt, ...)
  130. {
  131.    // helper function to quickly add an entry to an interlocutor's RTF chat window
  132.  
  133.    // {\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard
  134.    // This is some {\b bold} text.\par
  135.    // }
  136.    // NOTE: color table indices are 1-based
  137.  
  138.    static const wchar_t rtf_template[] = L"{\\cf%d\\b %s}\\par\n"
  139.                                          L"   %s\\par\n"
  140.                                          L"}\n";
  141.    static const int template_length = WCHAR_SIZEOF (rtf_template) - 6 - 2; // don't take in account closing brace, it's counted in the header
  142.    va_list argptr;
  143.    int sender_length;
  144.    int text_length;
  145.    int smiley_index;
  146.    smiley_t *smiley;
  147.    wchar_t *smiley_text;
  148.    wchar_t *after_smiley;
  149.  
  150.    // if dialog is just starting, we need to insert a RTF header
  151.    if (interlocutor->dialogtext == NULL)
  152.    {
  153.       interlocutor->dialogtext = (wchar_t *) SAFE_malloc (WCHAR_SIZEOF (rtf_header), sizeof (wchar_t), false); // allocate space for it
  154.       wcscpy_s (interlocutor->dialogtext, WCHAR_SIZEOF (rtf_header), rtf_header); // copy RTF header
  155.       interlocutor->dialogtext_size = WCHAR_SIZEOF (rtf_header); // save RTF header length
  156.    }
  157.  
  158.    // concatenate all the arguments in one string, but have a space before and after it
  159.    wcscpy_s (text_buffer, WCHAR_SIZEOF (text_buffer), L" ");
  160.    va_start (argptr, fmt);
  161.    vswprintf_s (&text_buffer[1], WCHAR_SIZEOF (text_buffer), fmt, argptr);
  162.    va_end (argptr);
  163.    wcscat_s (text_buffer, WCHAR_SIZEOF (text_buffer), L" ");
  164.  
  165.    // as long as there are smilies in this text, replace them with their equivalent data
  166.    for (smiley_index = 0; smiley_index < smiley_count; smiley_index++)
  167.    {
  168.       smiley = &smilies[smiley_index]; // quick access to smiley
  169.  
  170.       while ((smiley_text = wcsistr (text_buffer, smiley->name)) != NULL)
  171.       {
  172.          after_smiley = smiley_text + wcslen (smiley->name);
  173.          memmove (smiley_text + smiley->rtf_len, after_smiley, (wcslen (after_smiley) + 1) * sizeof (wchar_t));
  174.          memcpy (smiley_text, smiley->rtf_data, smiley->rtf_len * sizeof (wchar_t));
  175.       }
  176.    }
  177.  
  178.    // get sender and text lengths
  179.    sender_length = wcslen (sender);
  180.    text_length = wcslen (text_buffer);
  181.  
  182.    // resize the chat text buffer
  183.    interlocutor->dialogtext = (wchar_t *) SAFE_realloc (interlocutor->dialogtext,
  184.                                                         interlocutor->dialogtext_size,
  185.                                                         interlocutor->dialogtext_size + template_length + 1 + sender_length + text_length,
  186.                                                         sizeof (wchar_t), false);
  187.  
  188.    // append the message to the chat text and save the new text length (overwrite the closing brace)
  189.    swprintf_s (&interlocutor->dialogtext[wcslen (interlocutor->dialogtext) - 2],
  190.                template_length + 1 + sender_length + text_length + 2 + 1, // +1 for null terminator
  191.                rtf_template, (is_localsender ? 2 : 1), sender, text_buffer);
  192.    interlocutor->dialogtext_size += template_length + 1 + sender_length + text_length; // save new string length
  193.  
  194.    // and tell our chat window there's a new message to display
  195.    interlocutor->update_dialog = true;
  196.  
  197.    return; // finished
  198. }
  199.  
  200.  
  201. void Interlocutor_Notify (interlocutor_t *interlocutor, const wchar_t *fmt, ...)
  202. {
  203.    // helper function to quickly add an entry to an interlocutor's RTF chat window
  204.  
  205.    // {\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard
  206.    // This is some {\b bold} text.\par
  207.    // }
  208.    // NOTE: color table indices are 1-based
  209.  
  210.    static const wchar_t rtf_template[] = L"{\\cf4\\fs16\\i • %s}\\par\n"
  211.                                          L"}\n";
  212.    static const int template_length = WCHAR_SIZEOF (rtf_template) - 2 - 2; // don't take in account closing brace, it's counted in the header
  213.    va_list argptr;
  214.    int text_length;
  215.  
  216.    // if dialog is just starting, we need to insert a RTF header
  217.    if (interlocutor->dialogtext == NULL)
  218.    {
  219.       interlocutor->dialogtext = (wchar_t *) SAFE_malloc (WCHAR_SIZEOF (rtf_header), sizeof (wchar_t), false); // allocate space for it
  220.       wcscpy_s (interlocutor->dialogtext, WCHAR_SIZEOF (rtf_header), rtf_header); // copy RTF header
  221.       interlocutor->dialogtext_size = WCHAR_SIZEOF (rtf_header); // save RTF header length
  222.    }
  223.  
  224.    // concatenate all the arguments in one string
  225.    va_start (argptr, fmt);
  226.    vswprintf_s (text_buffer, WCHAR_SIZEOF (text_buffer), fmt, argptr);
  227.    va_end (argptr);
  228.  
  229.    // get text length
  230.    text_length = wcslen (text_buffer);
  231.  
  232.    // resize the chat text buffer
  233.    interlocutor->dialogtext = (wchar_t *) SAFE_realloc (interlocutor->dialogtext,
  234.                                                         interlocutor->dialogtext_size,
  235.                                                         interlocutor->dialogtext_size + template_length + text_length,
  236.                                                         sizeof (wchar_t), false);
  237.  
  238.    // append the message to the chat text and save the new text length (overwrite the closing brace)
  239.    swprintf_s (&interlocutor->dialogtext[wcslen (interlocutor->dialogtext) - 2],
  240.                template_length + text_length + 2 + 1, // +1 for null terminator
  241.                rtf_template, text_buffer);
  242.    interlocutor->dialogtext_size += template_length + text_length; // save new string length
  243.  
  244.    // and tell our chat window there's a new message to display
  245.    interlocutor->update_dialog = true;
  246.  
  247.    return; // finished
  248. }
  249.