GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/charcreatedialog.cpp Lines: 1 460 0.2 %
Date: 2020-06-04 Branches: 2 764 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
 *
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, std::string(),
83
        LoseFocusOnTab_true, nullptr, std::string(), false)),
84
    // TRANSLATORS: char create dialog label
85
    mNameLabel(new Label(this, _("Name:"))),
86
    mNextHairColorButton(nullptr),
87
    mPrevHairColorButton(nullptr),
88
    mHairColorLabel(nullptr),
89
    mHairColorNameLabel(nullptr),
90
    mNextHairStyleButton(nullptr),
91
    mPrevHairStyleButton(nullptr),
92
    mHairStyleLabel(nullptr),
93
    mHairStyleNameLabel(nullptr),
94
    mNextRaceButton(nullptr),
95
    mPrevRaceButton(nullptr),
96
    mRaceLabel(nullptr),
97
    mRaceNameLabel(nullptr),
98
    mNextLookButton(nullptr),
99
    mPrevLookButton(nullptr),
100
    mLookLabel(nullptr),
101
    mLookNameLabel(nullptr),
102
    // TRANSLATORS: char create dialog button
103
    mActionButton(new Button(this, _("^"), "action", BUTTON_SKIN, this)),
104
    // TRANSLATORS: char create dialog button
105
    mRotateButton(new Button(this, _(">"), "rotate", BUTTON_SKIN, this)),
106
    mAttributeSlider(),
107
    mAttributeLabel(),
108
    mAttributeValue(),
109
    mAttributesLeft(new Label(this,
110
        // TRANSLATORS: char create dialog label
111
        strprintf(_("Please distribute %d points"), 99))),
112
    // TRANSLATORS: char create dialog button
113
    mCreateButton(new Button(this, _("Create"), "create", BUTTON_SKIN, this)),
114
    // TRANSLATORS: char create dialog button
115
    mCancelButton(new Button(this, _("Cancel"), "cancel", BUTTON_SKIN, this)),
116
    mPlayer(Being::createBeing(BeingId_zero,
117
            ActorType::Player,
118
            BeingTypeId_zero,
119
            nullptr)),
120
    mPlayerBox(new PlayerBox(this, mPlayer, "charcreate_playerbox.xml",
121
        "charcreate_selectedplayerbox.xml")),
122
    mGenderStrip(nullptr),
123
    mMaxPoints(0),
124
    mUsedPoints(0),
125
    mRace(CharDB::getMinRace()),
126
    mLook(0),
127
    mMinLook(CharDB::getMinLook()),
128
    mMaxLook(CharDB::getMaxLook()),
129
    mMinRace(CharDB::getMinRace()),
130
    mMaxRace(CharDB::getMaxRace()),
131
    mHairStyle(0),
132
    mHairColor(0),
133
    mMaxY(0U),
134
    mSlot(slot),
135
    mDefaultGender(Gender::FEMALE),
136
    mGender(Gender::UNSPECIFIED),
137
    maxHairColor(CharDB::getMaxHairColor()),
138
    minHairColor(CharDB::getMinHairColor()),
139
    maxHairStyle(CharDB::getMaxHairStyle()),
140
    minHairStyle(CharDB::getMinHairStyle()),
141
    mAction(0),
142
    mDirection(0),
143
    mShowHiddenGender(CharDB::getShowHiddenGender())
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
                if (mShowHiddenGender &&
290
                    serverFeatures->haveCharHiddenGender())
291
                {
292
                    // TRANSLATORS: one char size male character gender
293
                    mGenderStrip->addButton(_("M"), "m", true);
294
                    // TRANSLATORS: one char size hidden character gender
295
                    mGenderStrip->addButton(_("H"), "h", false);
296
                }
297
                else
298
                {
299
                    // TRANSLATORS: one char size male character gender
300
                    mGenderStrip->addButton(_("M"), "m", false);
301
                    // TRANSLATORS: one char size unknown character gender
302
                    mGenderStrip->addButton(_("U"), "u", true);
303
                }
304
            }
305
            else
306
            {
307
                // TRANSLATORS: one char size male character gender
308
                mGenderStrip->addButton(_("M"), "m", true);
309
                if (mShowHiddenGender &&
310
                    serverFeatures->haveCharHiddenGender())
311
                {
312
                    // TRANSLATORS: one char size hidden character gender
313
                    mGenderStrip->addButton(_("H"), "h", false);
314
                }
315
            }
316
317
            mGenderStrip->setVisible(Visible_true);
318
            add(mGenderStrip);
319
320
            mGenderStrip->setPosition(385, 130);
321
            mGenderStrip->setWidth(500);
322
            mGenderStrip->setHeight(50);
323
        }
324
        else
325
        {
326
            mGender = Being::intToGender(CAST_U8(forceGender));
327
            mPlayer->setGender(mGender);
328
        }
329
    }
330
331
    mPlayerBox->setWidth(74);
332
333
    mNameField->setActionEventId("create");
334
    mNameField->addActionListener(this);
335
336
    mPlayerBox->setDimension(Rect(360, 0, 110, 90));
337
    mActionButton->setPosition(385, 100);
338
    mRotateButton->setPosition(415, 100);
339
340
    mNameLabel->setPosition(mPadding, 2);
341
    mNameField->setDimension(Rect(60, 2,
342
        300, mNameField->getHeight()));
343
344
    const uint32_t labelPadding = getOption("labelPadding", 2);
345
    const uint32_t leftX = 120 + mPadding;
346
    const uint32_t rightX = 300 + mPadding;
347
    const uint32_t labelX = mPadding;
348
    uint32_t nameX = leftX + labelPadding;
349
    uint32_t y = 30;
350
    if (mPrevHairColorButton != nullptr)
351
        nameX += mPrevHairColorButton->getWidth();
352
    else if (mPrevHairStyleButton != nullptr)
353
        nameX += mPrevHairStyleButton->getWidth();
354
    else if (mPrevLookButton != nullptr)
355
        nameX += mPrevLookButton->getWidth();
356
    else if (mPrevRaceButton != nullptr)
357
        nameX += mPrevRaceButton->getWidth();
358
359
    if (maxHairColor > minHairColor)
360
    {
361
        mPrevHairColorButton->setPosition(leftX, y);
362
        mNextHairColorButton->setPosition(rightX, y);
363
        y += 5;
364
        mHairColorLabel->setPosition(labelX, y);
365
        mHairColorNameLabel->setPosition(nameX, y);
366
        y += 24;
367
    }
368
    if (maxHairStyle > minHairStyle)
369
    {
370
        mPrevHairStyleButton->setPosition(leftX, y);
371
        mNextHairStyleButton->setPosition(rightX, y);
372
        y += 5;
373
        mHairStyleLabel->setPosition(labelX, y);
374
        mHairStyleNameLabel->setPosition(nameX, y);
375
        y += 24;
376
    }
377
378
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
379
    {
380
        if (mPrevLookButton != nullptr)
381
            mPrevLookButton->setPosition(leftX, y);
382
        if (mNextLookButton != nullptr)
383
            mNextLookButton->setPosition(rightX, y);
384
        y += 5;
385
        if (mLookLabel != nullptr)
386
            mLookLabel->setPosition(labelX, y);
387
        if (mLookNameLabel != nullptr)
388
            mLookNameLabel->setPosition(nameX, y);  // 93
389
        y += 24;
390
    }
391
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
392
    {
393
        if (mPrevRaceButton != nullptr)
394
            mPrevRaceButton->setPosition(leftX, y);
395
        if (mNextRaceButton != nullptr)
396
            mNextRaceButton->setPosition(rightX, y);
397
        y += 5;
398
        if (mRaceLabel != nullptr)
399
            mRaceLabel->setPosition(labelX, y);
400
        if (mRaceNameLabel != nullptr)
401
            mRaceNameLabel->setPosition(nameX, y);
402
    }
403
    mMaxY = y + 29 + getTitlePadding();
404
405
    updateSliders();
406
    setButtonsPosition(w, h);
407
408
    add(mPlayerBox);
409
    add(mNameField);
410
    add(mNameLabel);
411
412
    if (maxHairColor > minHairColor)
413
    {
414
        add(mNextHairColorButton);
415
        add(mPrevHairColorButton);
416
        add(mHairColorLabel);
417
        add(mHairColorNameLabel);
418
    }
419
420
    if (maxHairStyle > minHairStyle)
421
    {
422
        add(mNextHairStyleButton);
423
        add(mPrevHairStyleButton);
424
        add(mHairStyleLabel);
425
        add(mHairStyleNameLabel);
426
    }
427
    add(mActionButton);
428
    add(mRotateButton);
429
430
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
431
    {
432
        add(mNextLookButton);
433
        add(mPrevLookButton);
434
        add(mLookLabel);
435
        add(mLookNameLabel);
436
    }
437
438
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
439
    {
440
        add(mNextRaceButton);
441
        add(mPrevRaceButton);
442
        add(mRaceLabel);
443
        add(mRaceNameLabel);
444
    }
445
446
    add(mAttributesLeft);
447
    add(mCreateButton);
448
    add(mCancelButton);
449
450
    center();
451
    setVisible(Visible_true);
452
    mNameField->requestFocus();
453
454
    updateHair();
455
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
456
        updateRace();
457
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
458
        updateLook();
459
    updatePlayer();
460
461
    addKeyListener(this);
462
}
463
464
CharCreateDialog::~CharCreateDialog()
465
{
466
    delete2(mPlayer)
467
468
    if (charServerHandler != nullptr)
469
        charServerHandler->setCharCreateDialog(nullptr);
470
}
471
472
void CharCreateDialog::action(const ActionEvent &event)
473
{
474
    const std::string &id = event.getId();
475
    if (id == "create")
476
    {
477
        if (getName().length() >= 4)
478
        {
479
            // Attempt to create the character
480
            mCreateButton->setEnabled(false);
481
482
            STD_VECTOR<int> atts;
483
            const size_t sz = mAttributeSlider.size();
484
            for (size_t i = 0; i < sz; i++)
485
            {
486
                atts.push_back(CAST_S32(
487
                    mAttributeSlider[i]->getValue()));
488
            }
489
            for (size_t i = sz; i < 6; i ++)
490
                atts.push_back(1);
491
492
            const int characterSlot = mSlot;
493
494
            charServerHandler->newCharacter(getName(),
495
                characterSlot,
496
                mGender,
497
                mHairStyle,
498
                mHairColor,
499
                CAST_U8(mRace),
500
                CAST_U8(mLook),
501
                atts);
502
        }
503
        else
504
        {
505
            CREATEWIDGET(OkDialog,
506
                // TRANSLATORS: char creation error
507
                _("Error"),
508
                // TRANSLATORS: char creation error
509
                _("Your name needs to be at least 4 characters."),
510
                // TRANSLATORS: ok dialog button
511
                _("OK"),
512
                DialogType::ERROR,
513
                Modal_true,
514
                ShowCenter_true,
515
                nullptr,
516
                260);
517
        }
518
    }
519
    else if (id == "cancel")
520
    {
521
        scheduleDelete();
522
    }
523
    else if (id == "nextcolor")
524
    {
525
        mHairColor ++;
526
        updateHair();
527
    }
528
    else if (id == "prevcolor")
529
    {
530
        mHairColor --;
531
        updateHair();
532
    }
533
    else if (id == "nextstyle")
534
    {
535
        mHairStyle ++;
536
        updateHair();
537
    }
538
    else if (id == "prevstyle")
539
    {
540
        mHairStyle --;
541
        updateHair();
542
    }
543
    else if (id == "nextrace")
544
    {
545
        mRace ++;
546
        updateRace();
547
    }
548
    else if (id == "prevrace")
549
    {
550
        mRace --;
551
        updateRace();
552
    }
553
    else if (id == "nextlook")
554
    {
555
        mLook ++;
556
        updateLook();
557
    }
558
    else if (id == "prevlook")
559
    {
560
        mLook --;
561
        updateLook();
562
    }
563
    else if (id == "statslider")
564
    {
565
        updateSliders();
566
    }
567
    else if (id == "action")
568
    {
569
        mAction ++;
570
        if (mAction >= 5)
571
            mAction = 0;
572
        updatePlayer();
573
    }
574
    else if (id == "rotate")
575
    {
576
        mDirection ++;
577
        if (mDirection >= 4)
578
            mDirection = 0;
579
        updatePlayer();
580
    }
581
    else if (id == "gender_m")
582
    {
583
        mGender = Gender::MALE;
584
        mPlayer->setGender(Gender::MALE);
585
    }
586
    else if (id == "gender_f")
587
    {
588
        mGender = Gender::FEMALE;
589
        mPlayer->setGender(Gender::FEMALE);
590
    }
591
    else if (id == "gender_u")
592
    {
593
        mGender = Gender::UNSPECIFIED;
594
        mPlayer->setGender(mDefaultGender);
595
    }
596
    else if (id == "gender_h")
597
    {
598
        mGender = Gender::HIDDEN;
599
        mPlayer->setGender(Gender::HIDDEN);
600
    }
601
}
602
603
std::string CharCreateDialog::getName() const
604
{
605
    std::string name = mNameField->getText();
606
    trim(name);
607
    return name;
608
}
609
610
void CharCreateDialog::updateSliders()
611
{
612
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
613
    {
614
        // Update captions
615
        mAttributeValue[i]->setCaption(
616
                toString(CAST_S32(mAttributeSlider[i]->getValue())));
617
        mAttributeValue[i]->adjustSize();
618
    }
619
620
    // Update distributed points
621
    const int pointsLeft = mMaxPoints - getDistributedPoints();
622
    if (pointsLeft == 0)
623
    {
624
        // TRANSLATORS: char create dialog label
625
        mAttributesLeft->setCaption(_("Character stats OK"));
626
        mCreateButton->setEnabled(true);
627
    }
628
    else
629
    {
630
        mCreateButton->setEnabled(false);
631
        if (pointsLeft > 0)
632
        {
633
            mAttributesLeft->setCaption(
634
                // TRANSLATORS: char create dialog label
635
                strprintf(_("Please distribute %d points"), pointsLeft));
636
        }
637
        else
638
        {
639
            mAttributesLeft->setCaption(
640
                // TRANSLATORS: char create dialog label
641
                strprintf(_("Please remove %d points"), -pointsLeft));
642
        }
643
    }
644
645
    mAttributesLeft->adjustSize();
646
}
647
648
void CharCreateDialog::unlock()
649
{
650
    mCreateButton->setEnabled(true);
651
}
652
653
int CharCreateDialog::getDistributedPoints() const
654
{
655
    unsigned int points = 0;
656
657
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
658
        points += CAST_U32(mAttributeSlider[i]->getValue());
659
    return CAST_S32(points);
660
}
661
662
void CharCreateDialog::setAttributes(const StringVect &labels,
663
                                     int available,
664
                                     const int min, const int max)
665
{
666
    size_t sz;
667
668
    if (min == max || available == 0)
669
    {
670
        sz = 0U;
671
        available = 0;
672
    }
673
    else
674
    {
675
        sz = labels.size();
676
    }
677
678
    mMaxPoints = available;
679
680
    for (size_t i = 0; i < mAttributeLabel.size(); i++)
681
    {
682
        remove(mAttributeLabel[i]);
683
        delete2(mAttributeLabel[i])
684
        remove(mAttributeSlider[i]);
685
        delete2(mAttributeSlider[i])
686
        remove(mAttributeValue[i]);
687
        delete2(mAttributeValue[i])
688
    }
689
690
    mAttributeLabel.resize(sz);
691
    mAttributeSlider.resize(sz);
692
    mAttributeValue.resize(sz);
693
694
    const uint32_t w = 480;
695
    uint32_t h = 350;
696
    uint32_t y = 89;
697
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
698
        y += 29;
699
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
700
        y += 29;
701
702
    for (size_t i = 0; i < sz; i++)
703
    {
704
        mAttributeLabel[i] = new Label(this, labels[i]);
705
        mAttributeLabel[i]->setWidth(70);
706
        mAttributeLabel[i]->setPosition(mPadding,
707
            y + CAST_S32(i * 24));
708
        mAttributeLabel[i]->adjustSize();
709
        add(mAttributeLabel[i]);
710
711
        mAttributeSlider[i] = new Slider(this, min, max, 1.0);
712
        mAttributeSlider[i]->setDimension(Rect(140 + mPadding,
713
            y + CAST_S32(i * 24),
714
            150,
715
            12));
716
        mAttributeSlider[i]->setActionEventId("statslider");
717
        mAttributeSlider[i]->addActionListener(this);
718
        add(mAttributeSlider[i]);
719
720
        mAttributeValue[i] = new Label(this, toString(min));
721
        mAttributeValue[i]->setPosition(295 + mPadding,
722
            y + CAST_S32(i * 24));
723
        add(mAttributeValue[i]);
724
    }
725
726
    updateSliders();
727
    if (available == 0)
728
    {
729
        mAttributesLeft->setVisible(Visible_false);
730
        h = y;
731
    }
732
    else
733
    {
734
        h = y +
735
            CAST_S32(sz) * 24 +
736
            mAttributesLeft->getHeight() +
737
            getPadding();
738
    }
739
    if (serverFeatures->haveCreateCharGender() &&
740
        features.getIntValue("forceCharGender") == -1 &&
741
        y < 160)
742
    {
743
        if (h < 160)
744
            h = 160;
745
    }
746
    if (h < mMaxY)
747
        h = mMaxY;
748
    if (serverFeatures->haveCreateCharGender())
749
    {
750
        const int forceGender = features.getIntValue("forceCharGender");
751
        if (forceGender == -1 && h < 180)
752
            h = 180;
753
        else if (h < 120)
754
            h = 120;
755
    }
756
    h += mCreateButton->getHeight();
757
758
    setContentSize(w, h);
759
    setButtonsPosition(w, h);
760
}
761
762
void CharCreateDialog::setDefaultGender(const GenderT gender)
763
{
764
    if (features.getIntValue("forceCharGender") != -1)
765
        return;
766
767
    mDefaultGender = gender;
768
    mPlayer->setGender(gender);
769
}
770
771
void CharCreateDialog::updateHair()
772
{
773
    if (mHairStyle <= 0)
774
        mHairStyle = ItemDB::getNumOfHairstyles() - 1;
775
    else
776
        mHairStyle %= ItemDB::getNumOfHairstyles();
777
    if (mHairStyle < CAST_S32(minHairStyle)
778
        || mHairStyle > CAST_S32(maxHairStyle))
779
    {
780
        mHairStyle = minHairStyle;
781
    }
782
    const ItemInfo &item = ItemDB::get(-mHairStyle);
783
    if (mHairStyleNameLabel != nullptr)
784
    {
785
        mHairStyleNameLabel->setCaption(item.getName());
786
        mHairStyleNameLabel->resizeTo(150, 150);
787
    }
788
789
    if (ColorDB::getHairSize() != 0)
790
        mHairColor %= ColorDB::getHairSize();
791
    else
792
        mHairColor = 0;
793
    if (mHairColor < 0)
794
        mHairColor += ColorDB::getHairSize();
795
    if (mHairColor < CAST_S32(minHairColor)
796
        || mHairColor > CAST_S32(maxHairColor))
797
    {
798
        mHairColor = minHairColor;
799
    }
800
    if (mHairColorNameLabel != nullptr)
801
    {
802
        mHairColorNameLabel->setCaption(ColorDB::getHairColorName(
803
            fromInt(mHairColor, ItemColor)));
804
        mHairColorNameLabel->resizeTo(150, 150);
805
    }
806
807
    mPlayer->setSpriteColor(charServerHandler->hairSprite(),
808
        mHairStyle * -1,
809
        item.getDyeColorsString(fromInt(mHairColor, ItemColor)));
810
    updatePlayer();
811
}
812
813
void CharCreateDialog::updateRace()
814
{
815
    if (mRace < mMinRace)
816
        mRace = mMaxRace;
817
    else if (mRace > mMaxRace)
818
        mRace = mMinRace;
819
820
    updateLook();
821
}
822
823
void CharCreateDialog::updateLook()
824
{
825
    const ItemInfo &item = ItemDB::get(-100 - mRace);
826
    const int sz = item.getColorsSize();
827
    if (sz > 0 && serverFeatures->haveLookSelection())
828
    {
829
        if (mLook < 0)
830
            mLook = sz - 1;
831
        if (mLook > mMaxLook)
832
            mLook = mMinLook;
833
        if (mLook >= sz)
834
            mLook = mMinLook;
835
    }
836
    else
837
    {
838
        mLook = 0;
839
    }
840
    mPlayer->setSubtype(fromInt(mRace, BeingTypeId),
841
        CAST_U8(mLook));
842
    if (mRaceNameLabel != nullptr)
843
    {
844
        mRaceNameLabel->setCaption(item.getName());
845
        mRaceNameLabel->resizeTo(150, 150);
846
    }
847
    if (mLookNameLabel != nullptr)
848
    {
849
        mLookNameLabel->setCaption(item.getColorName(
850
            fromInt(mLook, ItemColor)));
851
        mLookNameLabel->resizeTo(150, 150);
852
    }
853
}
854
855
void CharCreateDialog::logic()
856
{
857
    BLOCK_START("CharCreateDialog::logic")
858
    if (mPlayer != nullptr)
859
        mPlayer->logic();
860
    BLOCK_END("CharCreateDialog::logic")
861
}
862
863
void CharCreateDialog::updatePlayer()
864
{
865
    if (mPlayer != nullptr)
866
    {
867
        mPlayer->setDirection(directions[mDirection]);
868
        mPlayer->setAction(actions[mAction], 0);
869
    }
870
}
871
872
void CharCreateDialog::keyPressed(KeyEvent &event)
873
{
874
    const InputActionT actionId = event.getActionId();
875
    PRAGMA45(GCC diagnostic push)
876
    PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
877
    switch (actionId)
878
    {
879
        case InputAction::GUI_CANCEL:
880
            event.consume();
881
            action(ActionEvent(mCancelButton,
882
                mCancelButton->getActionEventId()));
883
            break;
884
885
        default:
886
            break;
887
    }
888
    PRAGMA45(GCC diagnostic pop)
889
}
890
891
void CharCreateDialog::setButtonsPosition(const int w, const int h)
892
{
893
    const int h2 = h - 5 - mCancelButton->getHeight();
894
    if (mainGraphics->getHeight() < 480)
895
    {
896
        if (mMaxPoints != 0)
897
        {
898
            mCreateButton->setPosition(337, 160);
899
            mCancelButton->setPosition(337 + mCreateButton->getWidth(), 160);
900
        }
901
        else
902
        {
903
            mCancelButton->setPosition(
904
                w / 2,
905
                160);
906
            mCreateButton->setPosition(
907
                mCancelButton->getX() - 5 - mCreateButton->getWidth(),
908
                160);
909
        }
910
    }
911
    else
912
    {
913
        mCancelButton->setPosition(
914
            w / 2,
915
            h2);
916
        mCreateButton->setPosition(
917
            mCancelButton->getX() - 5 - mCreateButton->getWidth(),
918
            h2);
919
    }
920
    mAttributesLeft->setPosition(15, h2 - mAttributesLeft->getHeight());
921

3
}