Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 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 | |||
| 161 | pmbaty | 129 | void Interlocutor_Chat (interlocutor_t *interlocutor, const wchar_t *sender, bool is_localsender, const wchar_t *message) |
| 1 | pmbaty | 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 | int sender_length; |
||
| 143 | int text_length; |
||
| 144 | int smiley_index; |
||
| 145 | smiley_t *smiley; |
||
| 146 | wchar_t *smiley_text; |
||
| 147 | wchar_t *after_smiley; |
||
| 148 | |||
| 149 | // if dialog is just starting, we need to insert a RTF header |
||
| 150 | if (interlocutor->dialogtext == NULL) |
||
| 151 | { |
||
| 152 | interlocutor->dialogtext = (wchar_t *) SAFE_malloc (WCHAR_SIZEOF (rtf_header), sizeof (wchar_t), false); // allocate space for it |
||
| 153 | wcscpy_s (interlocutor->dialogtext, WCHAR_SIZEOF (rtf_header), rtf_header); // copy RTF header |
||
| 154 | interlocutor->dialogtext_size = WCHAR_SIZEOF (rtf_header); // save RTF header length |
||
| 155 | } |
||
| 156 | |||
| 157 | // concatenate all the arguments in one string, but have a space before and after it |
||
| 161 | pmbaty | 158 | swprintf_s (text_buffer, WCHAR_SIZEOF (text_buffer), L" %s ", message); |
| 1 | pmbaty | 159 | |
| 160 | // as long as there are smilies in this text, replace them with their equivalent data |
||
| 161 | for (smiley_index = 0; smiley_index < smiley_count; smiley_index++) |
||
| 162 | { |
||
| 163 | smiley = &smilies[smiley_index]; // quick access to smiley |
||
| 164 | |||
| 165 | while ((smiley_text = wcsistr (text_buffer, smiley->name)) != NULL) |
||
| 166 | { |
||
| 167 | after_smiley = smiley_text + wcslen (smiley->name); |
||
| 168 | memmove (smiley_text + smiley->rtf_len, after_smiley, (wcslen (after_smiley) + 1) * sizeof (wchar_t)); |
||
| 169 | memcpy (smiley_text, smiley->rtf_data, smiley->rtf_len * sizeof (wchar_t)); |
||
| 170 | } |
||
| 171 | } |
||
| 172 | |||
| 173 | // get sender and text lengths |
||
| 174 | sender_length = wcslen (sender); |
||
| 175 | text_length = wcslen (text_buffer); |
||
| 176 | |||
| 177 | // resize the chat text buffer |
||
| 178 | interlocutor->dialogtext = (wchar_t *) SAFE_realloc (interlocutor->dialogtext, |
||
| 179 | interlocutor->dialogtext_size, |
||
| 180 | interlocutor->dialogtext_size + template_length + 1 + sender_length + text_length, |
||
| 181 | sizeof (wchar_t), false); |
||
| 182 | |||
| 183 | // append the message to the chat text and save the new text length (overwrite the closing brace) |
||
| 184 | swprintf_s (&interlocutor->dialogtext[wcslen (interlocutor->dialogtext) - 2], |
||
| 185 | template_length + 1 + sender_length + text_length + 2 + 1, // +1 for null terminator |
||
| 186 | rtf_template, (is_localsender ? 2 : 1), sender, text_buffer); |
||
| 187 | interlocutor->dialogtext_size += template_length + 1 + sender_length + text_length; // save new string length |
||
| 188 | |||
| 189 | // and tell our chat window there's a new message to display |
||
| 190 | interlocutor->update_dialog = true; |
||
| 191 | |||
| 192 | return; // finished |
||
| 193 | } |
||
| 194 | |||
| 195 | |||
| 196 | void Interlocutor_Notify (interlocutor_t *interlocutor, const wchar_t *fmt, ...) |
||
| 197 | { |
||
| 198 | // helper function to quickly add an entry to an interlocutor's RTF chat window |
||
| 199 | |||
| 200 | // {\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard |
||
| 201 | // This is some {\b bold} text.\par |
||
| 202 | // } |
||
| 203 | // NOTE: color table indices are 1-based |
||
| 204 | |||
| 205 | static const wchar_t rtf_template[] = L"{\\cf4\\fs16\\i • %s}\\par\n" |
||
| 206 | L"}\n"; |
||
| 207 | static const int template_length = WCHAR_SIZEOF (rtf_template) - 2 - 2; // don't take in account closing brace, it's counted in the header |
||
| 208 | va_list argptr; |
||
| 209 | int text_length; |
||
| 210 | |||
| 211 | // if dialog is just starting, we need to insert a RTF header |
||
| 212 | if (interlocutor->dialogtext == NULL) |
||
| 213 | { |
||
| 214 | interlocutor->dialogtext = (wchar_t *) SAFE_malloc (WCHAR_SIZEOF (rtf_header), sizeof (wchar_t), false); // allocate space for it |
||
| 215 | wcscpy_s (interlocutor->dialogtext, WCHAR_SIZEOF (rtf_header), rtf_header); // copy RTF header |
||
| 216 | interlocutor->dialogtext_size = WCHAR_SIZEOF (rtf_header); // save RTF header length |
||
| 217 | } |
||
| 218 | |||
| 219 | // concatenate all the arguments in one string |
||
| 220 | va_start (argptr, fmt); |
||
| 221 | vswprintf_s (text_buffer, WCHAR_SIZEOF (text_buffer), fmt, argptr); |
||
| 222 | va_end (argptr); |
||
| 223 | |||
| 224 | // get text length |
||
| 225 | text_length = wcslen (text_buffer); |
||
| 226 | |||
| 227 | // resize the chat text buffer |
||
| 228 | interlocutor->dialogtext = (wchar_t *) SAFE_realloc (interlocutor->dialogtext, |
||
| 229 | interlocutor->dialogtext_size, |
||
| 230 | interlocutor->dialogtext_size + template_length + text_length, |
||
| 231 | sizeof (wchar_t), false); |
||
| 232 | |||
| 233 | // append the message to the chat text and save the new text length (overwrite the closing brace) |
||
| 234 | swprintf_s (&interlocutor->dialogtext[wcslen (interlocutor->dialogtext) - 2], |
||
| 235 | template_length + text_length + 2 + 1, // +1 for null terminator |
||
| 236 | rtf_template, text_buffer); |
||
| 237 | interlocutor->dialogtext_size += template_length + text_length; // save new string length |
||
| 238 | |||
| 239 | // and tell our chat window there's a new message to display |
||
| 240 | interlocutor->update_dialog = true; |
||
| 241 | |||
| 242 | return; // finished |
||
| 243 | } |