Go to most recent revision | Details | 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 | |||
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 | } |