Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
playerlistdlg.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** 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, see <http://www.gnu.org/licenses/>.
17*/
18
19// playerlistdlg.cpp : implementation file
20//
21
22#include "stdafx.h"
23#include "worldbuilder.h"
24#include "playerlistdlg.h"
25#include "MapObjectProps.h"
26#include "WorldBuilderDoc.h"
27#include "cundoable.h"
28#include "AddPlayerDialog.h"
32#include "GameLogic/SidesList.h"
33#include "GameClient/GameText.h"
35
36static const char* NEUTRAL_NAME_STR = "(neutral)";
37
38static Int thePrevCurPlyr = 0;
39
40static Bool islegalplayernamechar(char c)
41{
42 // note, spaces are NOT allowed.
43 return ::isalnum(c) || c == '_';
44}
45
46static void fixDefaultTeamName(SidesList& sides, AsciiString oldpname, AsciiString newpname)
47{
48 AsciiString tname;
49 tname.set("team");
50 tname.concat(oldpname);
51 TeamsInfo *ti = sides.findTeamInfo(tname);
52 if (ti)
53 {
54 tname.set("team");
55 tname.concat(newpname);
56 DEBUG_LOG(("rename team %s -> %s\n",ti->getDict()->getAsciiString(TheKey_teamName).str(),tname.str()));
57 ti->getDict()->setAsciiString(TheKey_teamName, tname);
58 ti->getDict()->setAsciiString(TheKey_teamOwner, newpname);
59 }
60 else
61 {
62 DEBUG_CRASH(("team not found"));
63 }
64}
65
66static void updateAllTeams(SidesList& sides, AsciiString oldpname, AsciiString newpname)
67{
68 Int numTeams = sides.getNumTeams();
69 for (Int i = 0; i < numTeams; ++i) {
70 TeamsInfo *teamInfo = sides.getTeamInfo(i);
71 if (teamInfo) {
72 Bool exists;
73 Dict *dict = teamInfo->getDict();
74
75 AsciiString teamOwner = dict->getAsciiString(TheKey_teamOwner, &exists);
76
77 if (exists && teamOwner.compare(oldpname) == 0) {
78 dict->setAsciiString(TheKey_teamOwner, newpname);
79 }
80 }
81 }
82}
83
84
85
86static void ensureValidPlayerName(Dict *d)
87{
88 // ensure there are no illegal chars in it. (in particular, no spaces!)
89 char buf[1024];
90 strcpy(buf, d->getAsciiString(TheKey_playerName).str());
91 for (char* p = buf; *p; ++p)
92 if (!islegalplayernamechar(*p))
93 *p = '_';
94 d->setAsciiString(TheKey_playerName, AsciiString(buf));
95}
96
97static AsciiString playerNameForUI(SidesList& sides, int i)
98{
99 AsciiString b = sides.getSideInfo(i)->getDict()->getAsciiString(TheKey_playerName);
100 if (b.isEmpty())
101 b = NEUTRAL_NAME_STR;
102 return b;
103}
104
105static AsciiString UIToInternal(SidesList& sides, const AsciiString& n)
106{
107 Int i;
108 for (i = 0; i < sides.getNumSides(); i++)
109 {
110 if (playerNameForUI(sides, i) == n)
111 return sides.getSideInfo(i)->getDict()->getAsciiString(TheKey_playerName);
112 }
113
114 DEBUG_CRASH(("ui name not found"));
116}
117
118static Bool containsToken(const AsciiString& cur_allies, const AsciiString& tokenIn)
119{
120 AsciiString name, token;
121
122 name = cur_allies;
123 while (name.nextToken(&token))
124 {
125 if (token == tokenIn)
126 return true;
127 }
128 return false;
129}
130
131static AsciiString removeDupsFromEnemies(const AsciiString& cur_allies, const AsciiString& cur_enemies)
132{
133 AsciiString new_enemies, tmp, token;
134
135 tmp = cur_enemies;
136 while (tmp.nextToken(&token))
137 {
138 if (containsToken(cur_allies, token))
139 continue;
140 if (!new_enemies.isEmpty())
141 new_enemies.concat(" ");
142 new_enemies.concat(token);
143 }
144 return new_enemies;
145}
146
147static AsciiString extractFromAlliesList(CListBox *alliesList, SidesList& sides)
148{
149 char buffer[1024];
150 AsciiString allies;
151 for (Int i = 0; i < alliesList->GetCount(); i++)
152 {
153 if (alliesList->GetSel(i) > 0)
154 {
155 alliesList->GetText(i, buffer);
156 AsciiString nm(buffer);
157 if (!allies.isEmpty())
158 allies.concat(" ");
159 allies.concat(UIToInternal(sides, nm));
160 }
161 }
162//DEBUG_LOG(("a/e is (%s)\n",allies.str()));
163 return allies;
164}
165
166static void buildAlliesList(CListBox *alliesList, SidesList& sides, const AsciiString& omitPlayer)
167{
168 Int i;
169 AsciiString name, token, oname;
170
171 alliesList->ResetContent();
172 for (i = 0; i < sides.getNumSides(); i++)
173 {
174 name = sides.getSideInfo(i)->getDict()->getAsciiString(TheKey_playerName);
175 if (name == omitPlayer || name.isEmpty())
176 continue;
177 name = playerNameForUI(sides, i);
178 alliesList->AddString(name.str());
179 }
180}
181
182static void selectAlliesList(CListBox *alliesList, SidesList& sides, const AsciiString& cur_allies)
183{
184 Int oindex_in_list;
185 AsciiString name, token, oname;
186
187 if (extractFromAlliesList(alliesList, sides) == cur_allies)
188 return;
189
190 alliesList->SetSel(-1, false);
191 name = cur_allies;
192 while (name.nextToken(&token))
193 {
194 Int i;
195 SidesInfo *si = sides.findSideInfo(token, &i);
196 if (!si)
197 {
198 DEBUG_CRASH(("player %s not found",token.str()));
199 continue;
200 }
201 // must re-find, since list is sorted
202 oindex_in_list = alliesList->FindStringExact(-1, playerNameForUI(sides, i).str());
203 if (oindex_in_list == -1)
204 {
205 DEBUG_CRASH(("hmm, should not happen"));
206 continue;
207 }
208 alliesList->SetSel(oindex_in_list, true);
209 }
210}
211
212// returns a str describing how t1 considers t2. (implies nothing about how t2 considers t1)
213static const char* calcRelationStr(SidesList& sides, int t1, int t2)
214{
215 const char* allied = "Ally";
216 const char* enemies = "Enemy";
217 const char* neutral = "Neutral";
218
219 SidesInfo* ti1;
220 SidesInfo* ti2;
221 AsciiString t2name;
222
223
224 // we use the relationship between our player's default teams.
225 ti1 = sides.getSideInfo(t1);
226 ti2 = sides.getSideInfo(t2);
227 t2name = ti2->getDict()->getAsciiString(TheKey_playerName);
228 if (containsToken(ti1->getDict()->getAsciiString(TheKey_playerAllies), t2name))
229 return allied;
230 else if (containsToken(ti1->getDict()->getAsciiString(TheKey_playerEnemies), t2name))
231 return enemies;
232
233 // no relation, so assume neutral
234 return neutral;
235}
236
238// PlayerListDlg dialog
239
240
241PlayerListDlg::PlayerListDlg(CWnd* pParent /*=NULL*/)
242 : CDialog(PlayerListDlg::IDD, pParent), m_updating(0)
243{
244 //{{AFX_DATA_INIT(PlayerListDlg)
245 // NOTE: the ClassWizard will add member initialization here
246 //}}AFX_DATA_INIT
247}
248
249
250void PlayerListDlg::DoDataExchange(CDataExchange* pDX)
251{
252 CDialog::DoDataExchange(pDX);
253 //{{AFX_DATA_MAP(PlayerListDlg)
254 // NOTE: the ClassWizard will add DDX and DDV calls here
255 //}}AFX_DATA_MAP
256}
257
258
259BEGIN_MESSAGE_MAP(PlayerListDlg, CDialog)
260 //{{AFX_MSG_MAP(PlayerListDlg)
261 ON_BN_CLICKED(IDC_NEWPLAYER, OnNewplayer)
262 ON_BN_CLICKED(IDC_EDITPLAYER, OnEditplayer)
263 ON_BN_CLICKED(IDC_REMOVEPLAYER, OnRemoveplayer)
264 ON_LBN_SELCHANGE(IDC_PLAYERS, OnSelchangePlayers)
265 ON_LBN_DBLCLK(IDC_PLAYERS, OnDblclkPlayers)
266 ON_LBN_SELCHANGE(IDC_ALLIESLIST, OnSelchangeAllieslist)
267 ON_LBN_SELCHANGE(IDC_ENEMIESLIST, OnSelchangeEnemieslist)
268 ON_BN_CLICKED(IDC_PLAYERISCOMPUTER, OnPlayeriscomputer)
269 ON_CBN_SELENDOK(IDC_PLAYERFACTION, OnEditchangePlayerfaction)
270 ON_BN_CLICKED(IDC_CHANGE_NAME, OnChangePlayername)
271 ON_EN_CHANGE(IDC_PLAYERDISPLAYNAME, OnChangePlayerdisplayname)
272 ON_BN_CLICKED(IDC_PlayerColor, OnColorPress)
273 ON_CBN_SELENDOK(IDC_PlayerColorCombo, OnSelectPlayerColor)
274 ON_BN_CLICKED(IDC_ADDSKIRMISHPLAYERS, OnAddskirmishplayers)
275 //}}AFX_MSG_MAP
276END_MESSAGE_MAP()
277
278 //ON_EN_CHANGE(IDC_PLAYERNAME, OnChangePlayername)
279
280
281// PlayerListDlg message handlers
282
284{
285 if (m_sides.getNumSides() >= MAX_PLAYER_COUNT - 1)
286 return;
287
288 AddPlayerDialog addPlyr("");
289 if (addPlyr.DoModal() != IDOK)
290 return;
291
292 AsciiString addedPTName = addPlyr.getAddedSide();
293
294 AsciiString pname;
295 UnicodeString pnameu;
296 Int num = 1;
297 do {
298 pname.format("player%04d",num);
299 pnameu.format(L"Player %04d's Display Name",num);
300 num++;
301 } while (m_sides.findSideInfo(pname));
302
303 Dict newPlayerDict;
304 newPlayerDict.setAsciiString(TheKey_playerName, pname);
305 newPlayerDict.setBool(TheKey_playerIsHuman, true);
306 newPlayerDict.setUnicodeString(TheKey_playerDisplayName, pnameu);
307 newPlayerDict.setAsciiString(TheKey_playerFaction, addedPTName);
308 newPlayerDict.setAsciiString(TheKey_playerEnemies, AsciiString(""));
309 newPlayerDict.setAsciiString(TheKey_playerAllies, AsciiString(""));
310
311#ifdef NOT_IN_USE
312 // auto-open the advanced prop editor
313 MapObjectProps editor(&newPlayerDict, "Create New Player", this);
314 if (editor.DoModal() == IDOK)
315#endif
316 {
317 if (newPlayerDict.getAsciiString(TheKey_playerName).isEmpty())
318 {
319 // sorry, no more than one neutral
320 }
321 else
322 {
323 ensureValidPlayerName(&newPlayerDict);
324 m_sides.addSide(&newPlayerDict);
325
326 Bool modified = m_sides.validateSides();
327 DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer"));
328 m_curPlayerIdx = m_sides.getNumSides()-1;
329 updateTheUI();
330 }
331 }
332}
333
335{
336 // TODO: the dialog referenced here has no ok or cancel buttons, so locks the editor
337 // re-enable this routine once it is not a guaranteed hang
338 AfxMessageBox("Implement me. (Sorry.)");
339 return;
340
341#if 0
342 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
343 AsciiString pnameold = playerDict->getAsciiString(TheKey_playerName);
344 Bool isneutral = pnameold.isEmpty();
345 if (isneutral)
346 return;
347
348 Dict playerDictCopy = *playerDict;
349 MapObjectProps editor(&playerDictCopy, "Edit Player", this);
350 if (editor.DoModal() == IDOK)
351 {
352 ensureValidPlayerName(&playerDictCopy);
353
354 if (playerDict->getAsciiString(TheKey_playerName) != playerDictCopy.getAsciiString(TheKey_playerName))
355 {
356 AsciiString tname;
357 tname.set("team");
358 tname.concat(playerDict->getAsciiString(TheKey_playerName));
360 if (count > 0)
361 {
362 CString msg;
363 msg.Format(IDS_RENAMING_INUSE_TEAM, count);
364 if (::AfxMessageBox(msg, MB_YESNO) == IDNO)
365 return;
366 }
367 }
368
369 *m_sides.getSideInfo(m_curPlayerIdx)->getDict() = playerDictCopy;
370
371 AsciiString pnamenew = playerDictCopy.getAsciiString(TheKey_playerName);
372 fixDefaultTeamName(m_sides, pnameold, pnamenew);
373
374 Bool modified = m_sides.validateSides();
375 DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnEditplayer"));
376
377 updateTheUI();
378 }
379#endif
380}
381
383{
384 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
385 AsciiString pname = playerDict->getAsciiString(TheKey_playerName);
386 Bool isneutral = pname.isEmpty();
387 if (isneutral)
388 return;
389
390 Int i;
391 Int count = 0;
392 for (i = 0; i < m_sides.getNumTeams(); i++)
393 {
394 Dict *tdict = m_sides.getTeamInfo(i)->getDict();
395 if (tdict->getAsciiString(TheKey_teamOwner) == pname)
396 {
397 count += MapObject::countMapObjectsWithOwner(tdict->getAsciiString(TheKey_teamName));
398 }
399 }
400
401 if (count > 0)
402 {
403 CString msg;
404 msg.Format(IDS_REMOVING_INUSE_TEAM, count);
405 if (::AfxMessageBox(msg, MB_YESNO) == IDNO)
406 return;
407 }
408
409 if (m_sides.getNumSides() <= 1)
410 return;
411
412 m_sides.removeSide(m_curPlayerIdx);
413try_again:
414 for (i = 0; i < m_sides.getNumTeams(); i++)
415 {
416 Dict *tdict = m_sides.getTeamInfo(i)->getDict();
417 if (tdict->getAsciiString(TheKey_teamOwner) == pname)
418 {
419 m_sides.removeTeam(i);
420 goto try_again;
421 }
422 }
423
424 Bool modified = m_sides.validateSides();
425 DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnRemoveplayer"));
426 updateTheUI();
427}
428
430{
431 CListBox *list = (CListBox*)GetDlgItem(IDC_PLAYERS);
432 m_curPlayerIdx = list->GetCurSel();
433 updateTheUI();
434}
435
437{
438 char buffer[1024];
439
440 if (m_updating)
441 return;
442
443 ++m_updating;
444
445 // make sure everything is canonical.
446 Bool modified = m_sides.validateSides();
447 DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::updateTheUI! (caller should do this)"));
448
449 if (m_curPlayerIdx < 0) m_curPlayerIdx = 0;
450 if (m_curPlayerIdx >= m_sides.getNumSides())
451 m_curPlayerIdx = m_sides.getNumSides()-1;
452
453 // update player list
454 CListBox *list = (CListBox*)GetDlgItem(IDC_PLAYERS);
455 list->ResetContent();
456
457 Int len = m_sides.getNumSides();
458 for (int i = 0; i < len; i++)
459 {
460 Dict *d = m_sides.getSideInfo(i)->getDict();
461 AsciiString name = d->getAsciiString(TheKey_playerName);
462 UnicodeString uni = d->getUnicodeString(TheKey_playerDisplayName);
463 AsciiString fmt;
464 if (name.isEmpty())
465 fmt = NEUTRAL_NAME_STR;
466 else
467 fmt.format("%s=\"%ls\"",name.str(),uni.str());
468 list->AddString(fmt.str());
469 }
470
471 Dict *pdict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
472 AsciiString cur_pname = pdict->getAsciiString(TheKey_playerName);
473 UnicodeString cur_pdname = pdict->getUnicodeString(TheKey_playerDisplayName);
474 Bool isNeutral = cur_pname.isEmpty();
475
476 // update player name
477 {
478 CWnd *playername = GetDlgItem(IDC_PLAYERNAME);
479 playername->EnableWindow(!isNeutral); // neutral names are not editable
480 playername->GetWindowText(buffer, sizeof(buffer)-2);
481 if (strcmp(cur_pname.str(), buffer) != 0)
482 playername->SetWindowText(cur_pname.str());
483 }
484
485 // update display name
486 {
487 CWnd *playerdname = GetDlgItem(IDC_PLAYERDISPLAYNAME);
488 playerdname->EnableWindow(!isNeutral); // neutral names are not editable
489 playerdname->GetWindowText(buffer, sizeof(buffer)-2);
490 AsciiString cur_pdnamea;
491 cur_pdnamea.translate(cur_pdname);
492 if (strcmp(cur_pdnamea.str(), buffer) != 0)
493 playerdname->SetWindowText(cur_pdnamea.str());
494 }
495
496 // update color button
497 {
498 RGBColor rgb;
499 Bool hasColor = false;
500 Int color = pdict->getInt(TheKey_playerColor, &hasColor);
501 if (hasColor) {
502 rgb.setFromInt(color);
503 } else {
504 AsciiString tmplname = pdict->getAsciiString(TheKey_playerFaction);
505 const PlayerTemplate* pt = ThePlayerTemplateStore->findPlayerTemplate(NAMEKEY(tmplname));
506 if (pt) {
507 rgb = *pt->getPreferredColor();
508 }
509 }
510 m_colorButton.setColor(rgb);
511 SelectColor(rgb);
512
513 }
514
515 // update control button
516 {
517 Bool isHuman = pdict->getBool(TheKey_playerIsHuman);
518 CButton *controller = (CButton*)GetDlgItem(IDC_PLAYERISCOMPUTER);
519 controller->SetCheck(isHuman ? 0 : 1);
520 controller->EnableWindow(!isNeutral);
521 }
522
523 // update factions popup
524 {
525 CComboBox *factions = (CComboBox*)GetDlgItem(IDC_PLAYERFACTION);
526 factions->ResetContent();
528 {
529 for (i = 0; i < ThePlayerTemplateStore->getPlayerTemplateCount(); i++)
530 {
531 AsciiString nm = ThePlayerTemplateStore->getNthPlayerTemplate(i)->getName();
532 factions->AddString(nm.str());
533 }
534 }
535 i = factions->FindStringExact(-1, pdict->getAsciiString(TheKey_playerFaction).str());
536 factions->SetCurSel(i);
537 }
538
539 // update allies & enemies
540 CListBox *allieslist = (CListBox*)GetDlgItem(IDC_ALLIESLIST);
541 CListBox *enemieslist = (CListBox*)GetDlgItem(IDC_ENEMIESLIST);
542 CListBox *regardOthers = (CListBox*)GetDlgItem(IDC_PLAYER_ATTITUDE_OUT);
543 CListBox *regardMe = (CListBox*)GetDlgItem(IDC_PLAYER_ATTITUDE_IN);
544
545 AsciiString cur_allies = m_sides.getSideInfo(m_curPlayerIdx)->getDict()->getAsciiString(TheKey_playerAllies);
546 buildAlliesList(allieslist, m_sides, cur_pname);
547 selectAlliesList(allieslist, m_sides, cur_allies);
548 allieslist->EnableWindow(!isNeutral);
549
550 AsciiString cur_enemies = m_sides.getSideInfo(m_curPlayerIdx)->getDict()->getAsciiString(TheKey_playerEnemies);
551 buildAlliesList(enemieslist, m_sides, cur_pname);
552 selectAlliesList(enemieslist, m_sides, cur_enemies);
553 enemieslist->EnableWindow(!isNeutral);
554
555 regardOthers->ResetContent();
556 regardMe->ResetContent();
557 const char* rstr;
558 AsciiString pname;
559 for (i = 0; i < m_sides.getNumSides(); i++)
560 {
561 pname = m_sides.getSideInfo(i)->getDict()->getAsciiString(TheKey_playerName);
562 if (pname.isEmpty() || pname == cur_pname)
563 continue; // skip neutral and self
564 pname = playerNameForUI(m_sides, i);
565
566 rstr = calcRelationStr(m_sides, m_curPlayerIdx, i);
567 sprintf(buffer, "%s: %s",pname.str(),rstr);
568 regardOthers->AddString(buffer);
569
570 rstr = calcRelationStr(m_sides, i, m_curPlayerIdx);
571 sprintf(buffer, "%s: %s",pname.str(),rstr);
572 regardMe->AddString(buffer);
573 }
574
575 list->SetCurSel(m_curPlayerIdx);
576
577 CWnd *newbtn = GetDlgItem(IDC_NEWPLAYER);
578 CWnd *editbtn = GetDlgItem(IDC_EDITPLAYER);
579 CWnd *rmvbtn = GetDlgItem(IDC_REMOVEPLAYER);
580 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
581 Bool isneutral = playerDict->getAsciiString(TheKey_playerName).isEmpty();
582 if( newbtn )
583 newbtn->EnableWindow(m_sides.getNumSides() < MAX_PLAYER_COUNT);
584 if( editbtn )
585 editbtn->EnableWindow(!isneutral);
586 if( rmvbtn )
587 rmvbtn->EnableWindow(m_sides.getNumSides() > 1 && !isneutral);
588
589 Invalidate();
590 UpdateWindow();
591
592 --m_updating;
593}
594
595
597{
598 CDialog::OnInitDialog();
599
600 m_updating = 0;
602 m_curPlayerIdx = thePrevCurPlyr;
603
604 CRect rect;
605 CWnd *item = GetDlgItem(IDC_PlayerColor);
606 if (item) {
607 item->GetWindowRect(&rect);
608 ScreenToClient(&rect);
609 DWORD style = item->GetStyle();
610 m_colorButton.Create("", style, rect, this, IDC_PlayerColor);
611 item->DestroyWindow();
612 }
613
614 updateTheUI();
616
617 return TRUE; // return TRUE unless you set the focus to a control
618 // EXCEPTION: OCX Property Pages should return FALSE
619}
620
625
627{
628 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
629 CColorDialog dlg;
630 if (dlg.DoModal() == IDOK) {
631 m_colorButton.setColor(CButtonShowColor::BGRtoRGB(dlg.GetColor()));
632 RGBColor color = m_colorButton.getColor();
633 playerDict->setInt(TheKey_playerColor, color.getAsInt());
634 }
635 updateTheUI();
636}
637
639{
640 Int numColors = TheMultiplayerSettings->getNumColors();
641 AsciiString colorName;
642
643 CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_PlayerColorCombo);
644 if (pCombo) {
645 for (Int c=0; c<numColors; ++c)
646 {
648 if (!def)
649 continue;
650 UnicodeString colorName = TheGameText->fetch(def->getTooltipName().str());
651 AsciiString str;
652 str.translate(colorName);
653 pCombo->AddString(str.str());
654 }
655 }
656}
657
659{
660 Int numColors = TheMultiplayerSettings->getNumColors();
661 AsciiString colorName;
662 Bool selected = false;
663
664 CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_PlayerColorCombo);
665 if (pCombo) {
666 for (Int c=0; c<numColors; ++c)
667 {
669 if (!def)
670 continue;
671 if (rgb.getAsInt() == def->getRGBValue().getAsInt()) {
672 pCombo->SetCurSel(c);
673 selected = true;
674 break;
675 }
676 }
677 if (!selected) {
678 pCombo->SetCurSel(-1);
679 }
680 }
681}
682
684{
685 CComboBox *pCombo = (CComboBox *)GetDlgItem(IDC_PlayerColorCombo);
686 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
687 if (pCombo && playerDict) {
688 CString str;
689 pCombo->GetWindowText(str);
690 Int index = -1;
691 Int numColors = TheMultiplayerSettings->getNumColors();
692 for (Int c=0; c<numColors; ++c)
693 {
695 if (!def)
696 continue;
697 UnicodeString colorName = TheGameText->fetch(def->getTooltipName().str());
698 AsciiString asciiColor;
699 asciiColor.translate(colorName);
700
701 if (str == asciiColor.str()) {
702 index = c;
703 break;
704 }
705 }
706 if (index >= 0) {
707 Int color = TheMultiplayerSettings->getColor(c)->getColor();
708 playerDict->setInt(TheKey_playerColor, color);
709 }
710 }
711 updateTheUI();
712}
713
715{
716 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
717 AsciiString pname = playerDict->getAsciiString(TheKey_playerName);
718 Bool isneutral = pname.isEmpty();
719 if (isneutral)
720 return;
721
722 CListBox *allieslist = (CListBox*)GetDlgItem(IDC_ALLIESLIST);
723 AsciiString allies = extractFromAlliesList(allieslist, m_sides);
724
725 CListBox *enemieslist = (CListBox*)GetDlgItem(IDC_ENEMIESLIST);
726 AsciiString enemies = extractFromAlliesList(enemieslist, m_sides);
727
728 enemies = removeDupsFromEnemies(allies, enemies);
729
730 m_sides.getSideInfo(m_curPlayerIdx)->getDict()->setAsciiString(TheKey_playerAllies, allies);
731 m_sides.getSideInfo(m_curPlayerIdx)->getDict()->setAsciiString(TheKey_playerEnemies, enemies);
732
733 updateTheUI();
734}
735
740
742{
743 Bool modified = m_sides.validateSides();
744 DEBUG_ASSERTLOG(!modified,("had to clean up sides in CTeamsDialog::OnOK"));
745
747 SidesListUndoable *pUndo = new SidesListUndoable(m_sides, pDoc);
748 pDoc->AddAndDoUndoable(pUndo);
749 REF_PTR_RELEASE(pUndo); // belongs to pDoc now.
750
751 thePrevCurPlyr = m_curPlayerIdx;
752
753 CDialog::OnOK();
754}
755
757{
758 CDialog::OnCancel();
759}
760
762{
763 CButton *b = (CButton*)GetDlgItem(IDC_PLAYERISCOMPUTER);
764 m_sides.getSideInfo(m_curPlayerIdx)->getDict()->setBool(TheKey_playerIsHuman, b->GetCheck() == 0);
765
766 updateTheUI();
767}
768
770{
771 CComboBox *faction = (CComboBox*)GetDlgItem(IDC_PLAYERFACTION);
772
773 if (faction) {
774 // get the text out of the combo. If it is user-typed, sel will be -1, otherwise it will be >=0
775 CString theText;
776 Int sel = faction->GetCurSel();
777 if (sel >= 0) {
778 faction->GetLBText(sel, theText);
779 } else {
780 faction->GetWindowText(theText);
781 }
782 AsciiString name((LPCTSTR)theText);
783
784 Dict *pdict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
785 pdict->setAsciiString(TheKey_playerFaction, name);
786
787 updateTheUI();
788 }
789}
790
792{
793 CWnd *playername = GetDlgItem(IDC_PLAYERNAME);
794 char buf[1024];
795 playername->GetWindowText(buf, sizeof(buf)-2);
796
797 Dict *pdict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
798 AsciiString pnamenew(buf);
799 AsciiString pnameold = pdict->getAsciiString(TheKey_playerName);
800
801 if (pnameold == pnamenew)
802 return; // hmm, no change, so just punt.
803
804 if (m_sides.findSideInfo(pnamenew))
805 {
806 ::AfxMessageBox(IDS_NAME_IN_USE);
807 }
808 else
809 {
810 pdict->setAsciiString(TheKey_playerName, pnamenew);
811 ensureValidPlayerName(pdict);
812
813 updateAllTeams(m_sides, pnameold, pnamenew);
814 fixDefaultTeamName(m_sides, pnameold, pnamenew);
815 }
816
817 updateTheUI();
818}
819
821{
822 CWnd *playername = GetDlgItem(IDC_PLAYERDISPLAYNAME);
823 char buf[1024];
824 playername->GetWindowText(buf, sizeof(buf)-2);
825
826 Dict *pdict = m_sides.getSideInfo(m_curPlayerIdx)->getDict();
827
828 AsciiString tmp(buf);
829 UnicodeString pnamenew;
830 pnamenew.translate(tmp);
831 UnicodeString pnameold = pdict->getUnicodeString(TheKey_playerDisplayName);
832
833 if (pnameold == pnamenew)
834 return; // hmm, no change, so just punt.
835
836 pdict->setUnicodeString(TheKey_playerDisplayName, pnamenew);
837
838 updateTheUI();
839}
840
841static void addSide(SidesList *sides, AsciiString faction,
842 AsciiString playerName, UnsignedShort *playerUName)
843{
844 if (!sides->findSideInfo(playerName)) {
845
846 Dict newPlayerDict;
847 UnicodeString playerUStr;
848 playerUStr = playerUName;
849 newPlayerDict.setAsciiString(TheKey_playerName, playerName);
850 newPlayerDict.setBool(TheKey_playerIsHuman, false);
851 newPlayerDict.setUnicodeString(TheKey_playerDisplayName, playerUStr);
852 newPlayerDict.setAsciiString(TheKey_playerFaction, faction);
853 newPlayerDict.setAsciiString(TheKey_playerEnemies, AsciiString(""));
854 newPlayerDict.setAsciiString(TheKey_playerAllies, AsciiString(""));
855
856 ensureValidPlayerName(&newPlayerDict);
857 sides->addSide(&newPlayerDict);
858
859 Bool modified = sides->validateSides();
860 DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer"));
861 }
862}
863
865{
866 // PlyrCivilian
867
868 addSide(&m_sides, "FactionCivilian", "PlyrCivilian", L"PlyrCivilian");
869 addSide(&m_sides, "FactionAmerica", "SkirmishAmerica", L"SkirmishAmerica");
870 addSide(&m_sides, "FactionChina", "SkirmishChina", L"SkirmishChina");
871 addSide(&m_sides, "FactionGLA", "SkirmishGLA", L"SkirmishGLA");
872
873 addSide(&m_sides, "FactionAmericaAirForceGeneral", "SkirmishAmericaAirForceGeneral", L"SkirmishAmericaAirForceGeneral");
874 addSide(&m_sides, "FactionAmericaLaserGeneral", "SkirmishAmericaLaserGeneral", L"SkirmishAmericaLaserGeneral");
875 addSide(&m_sides, "FactionAmericaSuperWeaponGeneral", "SkirmishAmericaSuperWeaponGeneral", L"SkirmishAmericaSuperWeaponGeneral");
876 addSide(&m_sides, "FactionChinaTankGeneral", "SkirmishChinaTankGeneral", L"SkirmishChinaTankGeneral");
877 addSide(&m_sides, "FactionChinaNukeGeneral", "SkirmishChinaNukeGeneral", L"SkirmishChinaNukeGeneral");
878 addSide(&m_sides, "FactionChinaInfantryGeneral", "SkirmishChinaInfantryGeneral", L"SkirmishChinaInfantryGeneral");
879 addSide(&m_sides, "FactionGLADemolitionGeneral", "SkirmishGLADemolitionGeneral", L"SkirmishGLADemolitionGeneral");
880 addSide(&m_sides, "FactionGLAToxinGeneral", "SkirmishGLAToxinGeneral", L"SkirmishGLAToxinGeneral");
881 addSide(&m_sides, "FactionGLAStealthGeneral", "SkirmishGLAStealthGeneral", L"SkirmishGLAStealthGeneral");
882 updateTheUI();
883}
bool Bool
Definition BaseType.h:132
#define TRUE
Definition BaseType.h:109
unsigned short UnsignedShort
Definition BaseType.h:127
@ MAX_PLAYER_COUNT
max number of Players.
Definition GameCommon.h:113
#define DEBUG_ASSERTLOG(c, m)
Definition Debug.h:158
#define DEBUG_LOG(m)
Definition Debug.h:157
#define DEBUG_CRASH(m)
Definition Debug.h:192
GameTextInterface * TheGameText
Definition GameText.cpp:212
unsigned long DWORD
Definition bittype.h:57
MultiplayerSettings * TheMultiplayerSettings
The MultiplayerSettings singleton.
NameKeyType NAMEKEY(const AsciiString &name)
PlayerTemplateStore * ThePlayerTemplateStore
singleton instance of PlayerTemplateStore
SidesList * TheSidesList
singleton instance of SidesList
#define IDC_PLAYERFACTION
Definition resource.h:323
#define IDC_PlayerColor
Definition resource.h:509
#define IDC_REMOVEPLAYER
Definition resource.h:243
#define IDC_ADDSKIRMISHPLAYERS
Definition resource.h:245
#define IDC_EDITPLAYER
Definition resource.h:242
#define IDS_NAME_IN_USE
Definition resource.h:725
#define IDC_CHANGE_NAME
Definition resource.h:160
#define IDC_ENEMIESLIST
Definition resource.h:313
#define IDS_REMOVING_INUSE_TEAM
Definition resource.h:723
#define IDC_PLAYERISCOMPUTER
Definition resource.h:359
#define IDC_NEWPLAYER
Definition resource.h:241
#define IDC_PLAYER_ATTITUDE_IN
Definition resource.h:341
#define IDC_PLAYER_ATTITUDE_OUT
Definition resource.h:368
#define IDS_RENAMING_INUSE_TEAM
Definition resource.h:724
#define IDC_ALLIESLIST
Definition resource.h:311
#define IDC_PLAYERS
Definition resource.h:244
#define IDC_PlayerColorCombo
Definition resource.h:510
#define IDC_PLAYERDISPLAYNAME
Definition resource.h:365
#define IDC_PLAYERNAME
Definition resource.h:321
#define BOOL
Definition Wnd_File.h:57
Bool nextToken(AsciiString *token, const char *seps=NULL)
void concat(const AsciiString &stringSrc)
int compare(const AsciiString &stringSrc) const
const char * str() const
void set(const AsciiString &stringSrc)
static AsciiString TheEmptyString
void format(AsciiString format,...)
void translate(const UnicodeString &stringSrc)
Bool isEmpty() const
static Int BGRtoRGB(COLORREF color)
static CWorldBuilderDoc * GetActiveDoc()
void AddAndDoUndoable(Undoable *pUndo)
Definition Dict.h:67
Int getInt(NameKeyType key, Bool *exists=NULL) const
Definition Dict.cpp:284
void setAsciiString(NameKeyType key, const AsciiString &value)
Definition Dict.cpp:496
void setBool(NameKeyType key, Bool value)
Definition Dict.cpp:466
Bool getBool(NameKeyType key, Bool *exists=NULL) const
Definition Dict.cpp:269
void setUnicodeString(NameKeyType key, const UnicodeString &value)
Definition Dict.cpp:506
UnicodeString getUnicodeString(NameKeyType key, Bool *exists=NULL) const
Definition Dict.cpp:329
void setInt(NameKeyType key, Int value)
Definition Dict.cpp:476
AsciiString getAsciiString(NameKeyType key, Bool *exists=NULL) const
Definition Dict.cpp:314
static Int countMapObjectsWithOwner(const AsciiString &n)
RGBColor getRGBValue(void) const
AsciiString getTooltipName(void) const
afx_msg void OnNewplayer()
virtual void OnCancel()
afx_msg void OnChangePlayername()
afx_msg void OnSelectPlayerColor()
afx_msg void OnChangePlayerdisplayname()
virtual void OnOK()
virtual void DoDataExchange(CDataExchange *pDX)
afx_msg void OnAddskirmishplayers()
afx_msg void OnSelchangePlayers()
SidesList m_sides
afx_msg void OnColorPress()
afx_msg void OnPlayeriscomputer()
afx_msg void OnEditplayer()
afx_msg void OnRemoveplayer()
afx_msg void OnEditchangePlayerfaction()
afx_msg void OnSelchangeEnemieslist()
afx_msg void OnSelchangeAllieslist()
virtual BOOL OnInitDialog()
CButtonShowColor m_colorButton
PlayerListDlg(CWnd *pParent=NULL)
void SelectColor(RGBColor rgb)
afx_msg void OnDblclkPlayers()
void updateTheUI(void)
void PopulateColorComboBox(void)
const RGBColor * getPreferredColor() const
Dict * getDict()
Definition SidesList.h:69
SidesInfo * getSideInfo(Int side)
Definition SidesList.h:219
void addSide(const Dict *d)
Int getNumSides()
Definition SidesList.h:153
Bool validateSides(void)
SidesInfo * findSideInfo(AsciiString name, Int *index=NULL)
TeamsInfo * getTeamInfo(Int team)
Definition SidesList.h:209
Int getNumTeams()
Definition SidesList.h:165
TeamsInfo * findTeamInfo(AsciiString name, Int *index=NULL)
Dict * getDict()
Definition SidesList.h:88
const WideChar * str() const
void translate(const AsciiString &stringSrc)
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
Definition patch.cpp:411
MSG msg
Definition patch.cpp:409
#define REF_PTR_RELEASE(x)
Definition refcount.h:80
Int getAsInt() const
Definition BaseType.h:464
void setFromInt(Int c)
Definition BaseType.h:472