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

3
}