GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/charcreatedialog.cpp Lines: 1 433 0.2 %
Date: 2017-11-29 Branches: 2 742 0.3 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "gui/windows/charcreatedialog.h"
24
25
#include "configuration.h"
26
27
#include "enums/being/beingdirection.h"
28
29
#include "being/being.h"
30
31
#include "gui/windows/okdialog.h"
32
33
#include "gui/widgets/button.h"
34
#include "gui/windows/charselectdialog.h"
35
#include "gui/widgets/createwidget.h"
36
#include "gui/widgets/label.h"
37
#include "gui/widgets/playerbox.h"
38
#include "gui/widgets/slider.h"
39
#include "gui/widgets/tabstrip.h"
40
#include "gui/widgets/textfield.h"
41
42
#include "net/charserverhandler.h"
43
#include "net/serverfeatures.h"
44
45
#include "resources/iteminfo.h"
46
47
#include "resources/db/chardb.h"
48
#include "resources/db/colordb.h"
49
#include "resources/db/itemdb.h"
50
51
#include "utils/delete2.h"
52
#include "utils/gettext.h"
53
54
#include "debug.h"
55
56
#undef ERROR
57
58
static const BeingActionT actions[] =
59
{
60
    BeingAction::STAND,
61
    BeingAction::SIT,
62
    BeingAction::MOVE,
63
    BeingAction::ATTACK,
64
    BeingAction::DEAD
65
};
66
67
static const uint8_t directions[] =
68
{
69
    BeingDirection::DOWN,
70
    BeingDirection::RIGHT,
71
    BeingDirection::UP,
72
    BeingDirection::LEFT
73
};
74
75
CharCreateDialog::CharCreateDialog(CharSelectDialog *const parent,
76
                                   const int slot) :
77
    // TRANSLATORS: char create dialog name
78
    Window(_("New Character"), Modal_true, parent, "charcreate.xml"),
79
    ActionListener(),
80
    KeyListener(),
81
    mCharSelectDialog(parent),
82
    mNameField(new TextField(this, "")),
83
    // TRANSLATORS: char create dialog label
84
    mNameLabel(new Label(this, _("Name:"))),
85
    mNextHairColorButton(nullptr),
86
    mPrevHairColorButton(nullptr),
87
    mHairColorLabel(nullptr),
88
    mHairColorNameLabel(nullptr),
89
    mNextHairStyleButton(nullptr),
90
    mPrevHairStyleButton(nullptr),
91
    mHairStyleLabel(nullptr),
92
    mHairStyleNameLabel(nullptr),
93
    mNextRaceButton(nullptr),
94
    mPrevRaceButton(nullptr),
95
    mRaceLabel(nullptr),
96
    mRaceNameLabel(nullptr),
97
    mNextLookButton(nullptr),
98
    mPrevLookButton(nullptr),
99
    mLookLabel(nullptr),
100
    mLookNameLabel(nullptr),
101
    // TRANSLATORS: char create dialog button
102
    mActionButton(new Button(this, _("^"), "action", this)),
103
    // TRANSLATORS: char create dialog button
104
    mRotateButton(new Button(this, _(">"), "rotate", this)),
105
    mAttributeSlider(),
106
    mAttributeLabel(),
107
    mAttributeValue(),
108
    mAttributesLeft(new Label(this,
109
        // TRANSLATORS: char create dialog label
110
        strprintf(_("Please distribute %d points"), 99))),
111
    // TRANSLATORS: char create dialog button
112
    mCreateButton(new Button(this, _("Create"), "create", this)),
113
    // TRANSLATORS: char create dialog button
114
    mCancelButton(new Button(this, _("Cancel"), "cancel", this)),
115
    mPlayer(Being::createBeing(BeingId_zero,
116
            ActorType::Player,
117
            BeingTypeId_zero,
118
            nullptr)),
119
    mPlayerBox(new PlayerBox(this, mPlayer, "charcreate_playerbox.xml",
120
        "charcreate_selectedplayerbox.xml")),
121
    mGenderStrip(nullptr),
122
    mMaxPoints(0),
123
    mUsedPoints(0),
124
    mRace(CharDB::getMinRace()),
125
    mLook(0),
126
    mMinLook(CharDB::getMinLook()),
127
    mMaxLook(CharDB::getMaxLook()),
128
    mMinRace(CharDB::getMinRace()),
129
    mMaxRace(CharDB::getMaxRace()),
130
    mHairStyle(0),
131
    mHairColor(0),
132
    mMaxY(0U),
133
    mSlot(slot),
134
    mDefaultGender(Gender::FEMALE),
135
    mGender(Gender::UNSPECIFIED),
136
    maxHairColor(CharDB::getMaxHairColor()),
137
    minHairColor(CharDB::getMinHairColor()),
138
    maxHairStyle(CharDB::getMaxHairStyle()),
139
    minHairStyle(CharDB::getMinHairStyle()),
140
    mAction(0),
141
    mDirection(0)
142
{
143
    setStickyButtonLock(true);
144
    setSticky(true);
145
    setWindowName("NewCharacter");
146
147
    const int w = 480;
148
    const int h = 350;
149
    setContentSize(w, h);
150
151
    mPlayer->setGender(Gender::MALE);
152
    const STD_VECTOR<BeingSlot> &items = CharDB::getDefaultItems();
153
    int i = 1;
154
    for (STD_VECTOR<BeingSlot>::const_iterator it = items.begin(),
155
         it_fend = items.end();
156
         it != it_fend;
157
         ++ it, i ++)
158
    {
159
        const BeingSlot &beingSlot = *it;
160
        mPlayer->setSpriteCards(i,
161
            beingSlot.spriteId,
162
            beingSlot.cardsId);
163
    }
164
165
    if (maxHairColor == 0u)
166
        maxHairColor = ColorDB::getHairSize();
167
    if (maxHairStyle == 0u)
168
        maxHairStyle = ItemDB::getNumOfHairstyles();
169
170
    if (maxHairStyle != 0u)
171
    {
172
        mHairStyle = (CAST_U32(rand())
173
            % maxHairStyle) + minHairStyle;
174
    }
175
    else
176
    {
177
        mHairStyle = 0;
178
    }
179
    if (maxHairColor != 0u)
180
    {
181
        mHairColor = (CAST_U32(rand())
182
            % maxHairColor) + minHairColor;
183
    }
184
    else
185
    {
186
        mHairColor = 0;
187
    }
188
189
    mNameField->setMaximum(24);
190
191
    if (maxHairColor > minHairColor)
192
    {
193
        // TRANSLATORS: This is a narrow symbol used to denote 'next'.
194
        // You may change this symbol if your language uses another.
195
        // TRANSLATORS: char create dialog button
196
        mNextHairColorButton = new Button(this, _(">"), "nextcolor", this);
197
        // TRANSLATORS: This is a narrow symbol used to denote 'previous'.
198
        // You may change this symbol if your language uses another.
199
        // TRANSLATORS: char create dialog button
200
        mPrevHairColorButton = new Button(this, _("<"), "prevcolor", this);
201
        // TRANSLATORS: char create dialog label
202
        mHairColorLabel = new Label(this, _("Hair color:"));
203
        mHairColorNameLabel = new Label(this, "");
204
    }
205
206
    if (maxHairStyle > minHairStyle)
207
    {
208
        // TRANSLATORS: char create dialog button
209
        mNextHairStyleButton = new Button(this, _(">"), "nextstyle", this);
210
        // TRANSLATORS: char create dialog button
211
        mPrevHairStyleButton = new Button(this, _("<"), "prevstyle", this);
212
        // TRANSLATORS: char create dialog label
213
        mHairStyleLabel = new Label(this, _("Hair style:"));
214
        mHairStyleNameLabel = new Label(this, "");
215
    }
216
217
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
218
    {
219
        // TRANSLATORS: char create dialog button
220
        mNextRaceButton = new Button(this, _(">"), "nextrace", this);
221
        // TRANSLATORS: char create dialog button
222
        mPrevRaceButton = new Button(this, _("<"), "prevrace", this);
223
        // TRANSLATORS: char create dialog label
224
        mRaceLabel = new Label(this, _("Race:"));
225
        mRaceNameLabel = new Label(this, "");
226
    }
227
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
228
    {
229
        // TRANSLATORS: char create dialog button
230
        mNextLookButton = new Button(this, _(">"), "nextlook", this);
231
        // TRANSLATORS: char create dialog button
232
        mPrevLookButton = new Button(this, _("<"), "prevlook", this);
233
        // TRANSLATORS: char create dialog label
234
        mLookLabel = new Label(this, _("Look:"));
235
        mLookNameLabel = new Label(this, "");
236
    }
237
238
    if (serverFeatures->haveCreateCharGender())
239
    {
240
        const int forceGender = features.getIntValue("forceCharGender");
241
        if (forceGender == -1)
242
        {
243
            const int size = config.getIntValue("fontSize");
244
            mGenderStrip = new TabStrip(this,
245
                "gender_" + getWindowName(),
246
                size + 16);
247
            mGenderStrip->setPressFirst(false);
248
            mGenderStrip->addActionListener(this);
249
            mGenderStrip->setActionEventId("gender_");
250
            // TRANSLATORS: one char size female character gender
251
            mGenderStrip->addButton(_("F"), "f", false);
252
            if (features.getIntValue("forceAccountGender") == -1)
253
            {
254
                if (serverFeatures->haveCharOtherGender())
255
                {
256
                    // TRANSLATORS: one char size male character gender
257
                    mGenderStrip->addButton(_("M"), "m", true);
258
                    // TRANSLATORS: one char size other character gender
259
                    mGenderStrip->addButton(_("O"), "o", false);
260
                }
261
                else
262
                {
263
                    // TRANSLATORS: one char size male character gender
264
                    mGenderStrip->addButton(_("M"), "m", false);
265
                    // TRANSLATORS: one char size unknown character gender
266
                    mGenderStrip->addButton(_("U"), "u", true);
267
                }
268
            }
269
            else
270
            {
271
                // TRANSLATORS: one char size male character gender
272
                mGenderStrip->addButton(_("M"), "m", true);
273
                if (serverFeatures->haveCharOtherGender())
274
                {
275
                    // TRANSLATORS: one char size other character gender
276
                    mGenderStrip->addButton(_("O"), "o", false);
277
                }
278
            }
279
280
281
            mGenderStrip->setVisible(Visible_true);
282
            add(mGenderStrip);
283
284
            mGenderStrip->setPosition(385, 130);
285
            mGenderStrip->setWidth(500);
286
            mGenderStrip->setHeight(50);
287
        }
288
        else
289
        {
290
            mGender = Being::intToGender(CAST_U8(forceGender));
291
            mPlayer->setGender(mGender);
292
        }
293
    }
294
295
    mPlayerBox->setWidth(74);
296
297
    mNameField->setActionEventId("create");
298
    mNameField->addActionListener(this);
299
300
    mPlayerBox->setDimension(Rect(360, 0, 110, 90));
301
    mActionButton->setPosition(385, 100);
302
    mRotateButton->setPosition(415, 100);
303
304
    mNameLabel->setPosition(mPadding, 2);
305
    mNameField->setDimension(Rect(60, 2,
306
        300, mNameField->getHeight()));
307
308
    const uint32_t labelPadding = getOption("labelPadding", 2);
309
    const uint32_t leftX = 120 + mPadding;
310
    const uint32_t rightX = 300 + mPadding;
311
    const uint32_t labelX = mPadding;
312
    uint32_t nameX = leftX + labelPadding;
313
    uint32_t y = 30;
314
    if (mPrevHairColorButton != nullptr)
315
        nameX += mPrevHairColorButton->getWidth();
316
    else if (mPrevHairStyleButton != nullptr)
317
        nameX += mPrevHairStyleButton->getWidth();
318
    else if (mPrevLookButton != nullptr)
319
        nameX += mPrevLookButton->getWidth();
320
    else if (mPrevRaceButton != nullptr)
321
        nameX += mPrevRaceButton->getWidth();
322
323
    if (maxHairColor > minHairColor)
324
    {
325
        mPrevHairColorButton->setPosition(leftX, y);
326
        mNextHairColorButton->setPosition(rightX, y);
327
        y += 5;
328
        mHairColorLabel->setPosition(labelX, y);
329
        mHairColorNameLabel->setPosition(nameX, y);
330
        y += 24;
331
    }
332
    if (maxHairStyle > minHairStyle)
333
    {
334
        mPrevHairStyleButton->setPosition(leftX, y);
335
        mNextHairStyleButton->setPosition(rightX, y);
336
        y += 5;
337
        mHairStyleLabel->setPosition(labelX, y);
338
        mHairStyleNameLabel->setPosition(nameX, y);
339
        y += 24;
340
    }
341
342
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
343
    {
344
        if (mPrevLookButton != nullptr)
345
            mPrevLookButton->setPosition(leftX, y);
346
        if (mNextLookButton != nullptr)
347
            mNextLookButton->setPosition(rightX, y);
348
        y += 5;
349
        if (mLookLabel != nullptr)
350
            mLookLabel->setPosition(labelX, y);
351
        if (mLookNameLabel != nullptr)
352
            mLookNameLabel->setPosition(nameX, y);  // 93
353
        y += 24;
354
    }
355
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
356
    {
357
        if (mPrevRaceButton != nullptr)
358
            mPrevRaceButton->setPosition(leftX, y);
359
        if (mNextRaceButton != nullptr)
360
            mNextRaceButton->setPosition(rightX, y);
361
        y += 5;
362
        if (mRaceLabel != nullptr)
363
            mRaceLabel->setPosition(labelX, y);
364
        if (mRaceNameLabel != nullptr)
365
            mRaceNameLabel->setPosition(nameX, y);
366
    }
367
    mMaxY = y + 29 + getTitlePadding();
368
369
    updateSliders();
370
    setButtonsPosition(w, h);
371
372
    add(mPlayerBox);
373
    add(mNameField);
374
    add(mNameLabel);
375
376
    if (maxHairColor > minHairColor)
377
    {
378
        add(mNextHairColorButton);
379
        add(mPrevHairColorButton);
380
        add(mHairColorLabel);
381
        add(mHairColorNameLabel);
382
    }
383
384
    if (maxHairStyle > minHairStyle)
385
    {
386
        add(mNextHairStyleButton);
387
        add(mPrevHairStyleButton);
388
        add(mHairStyleLabel);
389
        add(mHairStyleNameLabel);
390
    }
391
    add(mActionButton);
392
    add(mRotateButton);
393
394
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
395
    {
396
        add(mNextLookButton);
397
        add(mPrevLookButton);
398
        add(mLookLabel);
399
        add(mLookNameLabel);
400
    }
401
402
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
403
    {
404
        add(mNextRaceButton);
405
        add(mPrevRaceButton);
406
        add(mRaceLabel);
407
        add(mRaceNameLabel);
408
    }
409
410
    add(mAttributesLeft);
411
    add(mCreateButton);
412
    add(mCancelButton);
413
414
    center();
415
    setVisible(Visible_true);
416
    mNameField->requestFocus();
417
418
    updateHair();
419
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
420
        updateRace();
421
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
422
        updateLook();
423
    updatePlayer();
424
425
    addKeyListener(this);
426
}
427
428
CharCreateDialog::~CharCreateDialog()
429
{
430
    delete2(mPlayer);
431
432
    if (charServerHandler != nullptr)
433
        charServerHandler->setCharCreateDialog(nullptr);
434
}
435
436
void CharCreateDialog::action(const ActionEvent &event)
437
{
438
    const std::string &id = event.getId();
439
    if (id == "create")
440
    {
441
        if (getName().length() >= 4)
442
        {
443
            // Attempt to create the character
444
            mCreateButton->setEnabled(false);
445
446
            STD_VECTOR<int> atts;
447
            const size_t sz = mAttributeSlider.size();
448
            for (size_t i = 0; i < sz; i++)
449
            {
450
                atts.push_back(CAST_S32(
451
                    mAttributeSlider[i]->getValue()));
452
            }
453
            for (size_t i = sz; i < 6; i ++)
454
                atts.push_back(1);
455
456
            const int characterSlot = mSlot;
457
458
            charServerHandler->newCharacter(getName(),
459
                characterSlot,
460
                mGender,
461
                mHairStyle,
462
                mHairColor,
463
                CAST_U8(mRace),
464
                CAST_U8(mLook),
465
                atts);
466
        }
467
        else
468
        {
469
            CREATEWIDGET(OkDialog,
470
                // TRANSLATORS: char creation error
471
                _("Error"),
472
                // TRANSLATORS: char creation error
473
                _("Your name needs to be at least 4 characters."),
474
                // TRANSLATORS: ok dialog button
475
                _("OK"),
476
                DialogType::ERROR,
477
                Modal_true,
478
                ShowCenter_true,
479
                nullptr,
480
                260);
481
        }
482
    }
483
    else if (id == "cancel")
484
    {
485
        scheduleDelete();
486
    }
487
    else if (id == "nextcolor")
488
    {
489
        mHairColor ++;
490
        updateHair();
491
    }
492
    else if (id == "prevcolor")
493
    {
494
        mHairColor --;
495
        updateHair();
496
    }
497
    else if (id == "nextstyle")
498
    {
499
        mHairStyle ++;
500
        updateHair();
501
    }
502
    else if (id == "prevstyle")
503
    {
504
        mHairStyle --;
505
        updateHair();
506
    }
507
    else if (id == "nextrace")
508
    {
509
        mRace ++;
510
        updateRace();
511
    }
512
    else if (id == "prevrace")
513
    {
514
        mRace --;
515
        updateRace();
516
    }
517
    else if (id == "nextlook")
518
    {
519
        mLook ++;
520
        updateLook();
521
    }
522
    else if (id == "prevlook")
523
    {
524
        mLook --;
525
        updateLook();
526
    }
527
    else if (id == "statslider")
528
    {
529
        updateSliders();
530
    }
531
    else if (id == "action")
532
    {
533
        mAction ++;
534
        if (mAction >= 5)
535
            mAction = 0;
536
        updatePlayer();
537
    }
538
    else if (id == "rotate")
539
    {
540
        mDirection ++;
541
        if (mDirection >= 4)
542
            mDirection = 0;
543
        updatePlayer();
544
    }
545
    else if (id == "gender_m")
546
    {
547
        mGender = Gender::MALE;
548
        mPlayer->setGender(Gender::MALE);
549
    }
550
    else if (id == "gender_f")
551
    {
552
        mGender = Gender::FEMALE;
553
        mPlayer->setGender(Gender::FEMALE);
554
    }
555
    else if (id == "gender_u")
556
    {
557
        mGender = Gender::UNSPECIFIED;
558
        mPlayer->setGender(mDefaultGender);
559
    }
560
    else if (id == "gender_o")
561
    {
562
        mGender = Gender::OTHER;
563
        mPlayer->setGender(Gender::OTHER);
564
    }
565
}
566
567
std::string CharCreateDialog::getName() const
568
{
569
    std::string name = mNameField->getText();
570
    trim(name);
571
    return name;
572
}
573
574
void CharCreateDialog::updateSliders()
575
{
576
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
577
    {
578
        // Update captions
579
        mAttributeValue[i]->setCaption(
580
                toString(CAST_S32(mAttributeSlider[i]->getValue())));
581
        mAttributeValue[i]->adjustSize();
582
    }
583
584
    // Update distributed points
585
    const int pointsLeft = mMaxPoints - getDistributedPoints();
586
    if (pointsLeft == 0)
587
    {
588
        // TRANSLATORS: char create dialog label
589
        mAttributesLeft->setCaption(_("Character stats OK"));
590
        mCreateButton->setEnabled(true);
591
    }
592
    else
593
    {
594
        mCreateButton->setEnabled(false);
595
        if (pointsLeft > 0)
596
        {
597
            mAttributesLeft->setCaption(
598
                // TRANSLATORS: char create dialog label
599
                strprintf(_("Please distribute %d points"), pointsLeft));
600
        }
601
        else
602
        {
603
            mAttributesLeft->setCaption(
604
                // TRANSLATORS: char create dialog label
605
                strprintf(_("Please remove %d points"), -pointsLeft));
606
        }
607
    }
608
609
    mAttributesLeft->adjustSize();
610
}
611
612
void CharCreateDialog::unlock()
613
{
614
    mCreateButton->setEnabled(true);
615
}
616
617
int CharCreateDialog::getDistributedPoints() const
618
{
619
    int points = 0;
620
621
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
622
        points += CAST_S32(mAttributeSlider[i]->getValue());
623
    return points;
624
}
625
626
void CharCreateDialog::setAttributes(const StringVect &labels,
627
                                     int available,
628
                                     const int min, const int max)
629
{
630
    size_t sz;
631
632
    if (min == max || available == 0)
633
    {
634
        sz = 0U;
635
        available = 0;
636
    }
637
    else
638
    {
639
        sz = labels.size();
640
    }
641
642
    mMaxPoints = available;
643
644
    for (size_t i = 0; i < mAttributeLabel.size(); i++)
645
    {
646
        remove(mAttributeLabel[i]);
647
        delete2(mAttributeLabel[i])
648
        remove(mAttributeSlider[i]);
649
        delete2(mAttributeSlider[i])
650
        remove(mAttributeValue[i]);
651
        delete2(mAttributeValue[i])
652
    }
653
654
    mAttributeLabel.resize(sz);
655
    mAttributeSlider.resize(sz);
656
    mAttributeValue.resize(sz);
657
658
    const uint32_t w = 480;
659
    uint32_t h = 350;
660
    uint32_t y = 89;
661
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
662
        y += 29;
663
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
664
        y += 29;
665
666
    for (size_t i = 0; i < sz; i++)
667
    {
668
        mAttributeLabel[i] = new Label(this, labels[i]);
669
        mAttributeLabel[i]->setWidth(70);
670
        mAttributeLabel[i]->setPosition(mPadding,
671
            y + CAST_S32(i * 24));
672
        mAttributeLabel[i]->adjustSize();
673
        add(mAttributeLabel[i]);
674
675
        mAttributeSlider[i] = new Slider(this, min, max, 1.0);
676
        mAttributeSlider[i]->setDimension(Rect(140 + mPadding,
677
            y + CAST_S32(i * 24),
678
            150,
679
            12));
680
        mAttributeSlider[i]->setActionEventId("statslider");
681
        mAttributeSlider[i]->addActionListener(this);
682
        add(mAttributeSlider[i]);
683
684
        mAttributeValue[i] = new Label(this, toString(min));
685
        mAttributeValue[i]->setPosition(295 + mPadding,
686
            y + CAST_S32(i * 24));
687
        add(mAttributeValue[i]);
688
    }
689
690
    updateSliders();
691
    if (available == 0)
692
    {
693
        mAttributesLeft->setVisible(Visible_false);
694
        h = y;
695
    }
696
    else
697
    {
698
        h = y +
699
            CAST_S32(sz) * 24 +
700
            mAttributesLeft->getHeight() +
701
            getPadding();
702
    }
703
    if (serverFeatures->haveCreateCharGender() &&
704
        features.getIntValue("forceCharGender") == -1 &&
705
        y < 160)
706
    {
707
        if (h < 160)
708
            h = 160;
709
    }
710
    if (h < mMaxY)
711
        h = mMaxY;
712
    if (serverFeatures->haveCreateCharGender())
713
    {
714
        const int forceGender = features.getIntValue("forceCharGender");
715
        if (forceGender == -1 && h < 180)
716
            h = 180;
717
        else if (h < 120)
718
            h = 120;
719
    }
720
    h += mCreateButton->getHeight();
721
722
    setContentSize(w, h);
723
    setButtonsPosition(w, h);
724
}
725
726
void CharCreateDialog::setDefaultGender(const GenderT gender)
727
{
728
    if (features.getIntValue("forceCharGender") != -1)
729
        return;
730
731
    mDefaultGender = gender;
732
    mPlayer->setGender(gender);
733
}
734
735
void CharCreateDialog::updateHair()
736
{
737
    if (mHairStyle <= 0)
738
        mHairStyle = ItemDB::getNumOfHairstyles() - 1;
739
    else
740
        mHairStyle %= ItemDB::getNumOfHairstyles();
741
    if (mHairStyle < CAST_S32(minHairStyle)
742
        || mHairStyle > CAST_S32(maxHairStyle))
743
    {
744
        mHairStyle = minHairStyle;
745
    }
746
    const ItemInfo &item = ItemDB::get(-mHairStyle);
747
    if (mHairStyleNameLabel != nullptr)
748
    {
749
        mHairStyleNameLabel->setCaption(item.getName());
750
        mHairStyleNameLabel->resizeTo(150, 150);
751
    }
752
753
    if (ColorDB::getHairSize() != 0)
754
        mHairColor %= ColorDB::getHairSize();
755
    else
756
        mHairColor = 0;
757
    if (mHairColor < 0)
758
        mHairColor += ColorDB::getHairSize();
759
    if (mHairColor < CAST_S32(minHairColor)
760
        || mHairColor > CAST_S32(maxHairColor))
761
    {
762
        mHairColor = minHairColor;
763
    }
764
    if (mHairColorNameLabel != nullptr)
765
    {
766
        mHairColorNameLabel->setCaption(ColorDB::getHairColorName(
767
            fromInt(mHairColor, ItemColor)));
768
        mHairColorNameLabel->resizeTo(150, 150);
769
    }
770
771
    mPlayer->setSpriteColor(charServerHandler->hairSprite(),
772
        mHairStyle * -1,
773
        item.getDyeColorsString(fromInt(mHairColor, ItemColor)));
774
    updatePlayer();
775
}
776
777
void CharCreateDialog::updateRace()
778
{
779
    if (mRace < mMinRace)
780
        mRace = mMaxRace;
781
    else if (mRace > mMaxRace)
782
        mRace = mMinRace;
783
784
    updateLook();
785
}
786
787
void CharCreateDialog::updateLook()
788
{
789
    const ItemInfo &item = ItemDB::get(-100 - mRace);
790
    const int sz = item.getColorsSize();
791
    if (sz > 0 && serverFeatures->haveLookSelection())
792
    {
793
        if (mLook < 0)
794
            mLook = sz - 1;
795
        if (mLook > mMaxLook)
796
            mLook = mMinLook;
797
        if (mLook >= sz)
798
            mLook = mMinLook;
799
    }
800
    else
801
    {
802
        mLook = 0;
803
    }
804
    mPlayer->setSubtype(fromInt(mRace, BeingTypeId),
805
        CAST_U8(mLook));
806
    if (mRaceNameLabel != nullptr)
807
    {
808
        mRaceNameLabel->setCaption(item.getName());
809
        mRaceNameLabel->resizeTo(150, 150);
810
    }
811
    if (mLookNameLabel != nullptr)
812
    {
813
        mLookNameLabel->setCaption(item.getColorName(
814
            fromInt(mLook, ItemColor)));
815
        mLookNameLabel->resizeTo(150, 150);
816
    }
817
}
818
819
void CharCreateDialog::logic()
820
{
821
    BLOCK_START("CharCreateDialog::logic")
822
    if (mPlayer != nullptr)
823
        mPlayer->logic();
824
    BLOCK_END("CharCreateDialog::logic")
825
}
826
827
void CharCreateDialog::updatePlayer()
828
{
829
    if (mPlayer != nullptr)
830
    {
831
        mPlayer->setDirection(directions[mDirection]);
832
        mPlayer->setAction(actions[mAction], 0);
833
    }
834
}
835
836
void CharCreateDialog::keyPressed(KeyEvent &event)
837
{
838
    const InputActionT actionId = event.getActionId();
839
    PRAGMA45(GCC diagnostic push)
840
    PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
841
    switch (actionId)
842
    {
843
        case InputAction::GUI_CANCEL:
844
            event.consume();
845
            action(ActionEvent(mCancelButton,
846
                mCancelButton->getActionEventId()));
847
            break;
848
849
        default:
850
            break;
851
    }
852
    PRAGMA45(GCC diagnostic pop)
853
}
854
855
void CharCreateDialog::setButtonsPosition(const int w, const int h)
856
{
857
    const int h2 = h - 5 - mCancelButton->getHeight();
858
    if (mainGraphics->getHeight() < 480)
859
    {
860
        if (mMaxPoints != 0)
861
        {
862
            mCreateButton->setPosition(337, 160);
863
            mCancelButton->setPosition(337 + mCreateButton->getWidth(), 160);
864
        }
865
        else
866
        {
867
            mCancelButton->setPosition(
868
                w / 2,
869
                160);
870
            mCreateButton->setPosition(
871
                mCancelButton->getX() - 5 - mCreateButton->getWidth(),
872
                160);
873
        }
874
    }
875
    else
876
    {
877
        mCancelButton->setPosition(
878
            w / 2,
879
            h2);
880
        mCreateButton->setPosition(
881
            mCancelButton->getX() - 5 - mCreateButton->getWidth(),
882
            h2);
883
    }
884
    mAttributesLeft->setPosition(15, h2 - mAttributesLeft->getHeight());
885

6
}