GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/charcreatedialog.cpp Lines: 1 458 0.2 %
Date: 2018-12-09 Branches: 2 754 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-2018  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
{
144
    setStickyButtonLock(true);
145
    setSticky(true);
146
    setWindowName("NewCharacter");
147
148
    const int w = 480;
149
    const int h = 350;
150
    setContentSize(w, h);
151
152
    mPlayer->setGender(Gender::MALE);
153
    const STD_VECTOR<BeingSlot> &items = CharDB::getDefaultItems();
154
    int i = 1;
155
    for (STD_VECTOR<BeingSlot>::const_iterator it = items.begin(),
156
         it_fend = items.end();
157
         it != it_fend;
158
         ++ it, i ++)
159
    {
160
        const BeingSlot &beingSlot = *it;
161
        mPlayer->setSpriteCards(i,
162
            beingSlot.spriteId,
163
            beingSlot.cardsId);
164
    }
165
166
    if (maxHairColor == 0U)
167
        maxHairColor = ColorDB::getHairSize();
168
    if (maxHairStyle == 0U)
169
        maxHairStyle = ItemDB::getNumOfHairstyles();
170
171
    if (maxHairStyle != 0U)
172
    {
173
        mHairStyle = (CAST_U32(rand())
174
            % maxHairStyle) + minHairStyle;
175
    }
176
    else
177
    {
178
        mHairStyle = 0;
179
    }
180
    if (maxHairColor != 0U)
181
    {
182
        mHairColor = (CAST_U32(rand())
183
            % maxHairColor) + minHairColor;
184
    }
185
    else
186
    {
187
        mHairColor = 0;
188
    }
189
190
    mNameField->setMaximum(24);
191
192
    if (maxHairColor > minHairColor)
193
    {
194
        mNextHairColorButton = new Button(this,
195
            // TRANSLATORS: This is a narrow symbol used to denote 'next'.
196
            // You may change this symbol if your language uses another.
197
            // TRANSLATORS: char create dialog button
198
            _(">"),
199
            "nextcolor",
200
            BUTTON_SKIN,
201
            this);
202
        mPrevHairColorButton = new Button(this,
203
            // TRANSLATORS: This is a narrow symbol used to denote 'previous'.
204
            // You may change this symbol if your language uses another.
205
            // TRANSLATORS: char create dialog button
206
            _("<"),
207
            "prevcolor",
208
             BUTTON_SKIN,
209
            this);
210
        // TRANSLATORS: char create dialog label
211
        mHairColorLabel = new Label(this, _("Hair color:"));
212
        mHairColorNameLabel = new Label(this, "");
213
    }
214
215
    if (maxHairStyle > minHairStyle)
216
    {
217
        mNextHairStyleButton = new Button(this,
218
            // TRANSLATORS: char create dialog button
219
            _(">"),
220
            "nextstyle",
221
            BUTTON_SKIN,
222
            this);
223
        mPrevHairStyleButton = new Button(this,
224
            // TRANSLATORS: char create dialog button
225
            _("<"),
226
            "prevstyle",
227
            BUTTON_SKIN,
228
            this);
229
        // TRANSLATORS: char create dialog label
230
        mHairStyleLabel = new Label(this, _("Hair style:"));
231
        mHairStyleNameLabel = new Label(this, "");
232
    }
233
234
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
235
    {
236
        mNextRaceButton = new Button(this,
237
            // TRANSLATORS: char create dialog button
238
            _(">"),
239
            "nextrace",
240
            BUTTON_SKIN,
241
            this);
242
        mPrevRaceButton = new Button(this,
243
            // TRANSLATORS: char create dialog button
244
            _("<"),
245
            "prevrace",
246
            BUTTON_SKIN,
247
            this);
248
        // TRANSLATORS: char create dialog label
249
        mRaceLabel = new Label(this, _("Race:"));
250
        mRaceNameLabel = new Label(this, "");
251
    }
252
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
253
    {
254
        mNextLookButton = new Button(this,
255
            // TRANSLATORS: char create dialog button
256
            _(">"),
257
            "nextlook",
258
            BUTTON_SKIN,
259
            this);
260
        mPrevLookButton = new Button(this,
261
            // TRANSLATORS: char create dialog button
262
            _("<"),
263
            "prevlook",
264
            BUTTON_SKIN,
265
            this);
266
        // TRANSLATORS: char create dialog label
267
        mLookLabel = new Label(this, _("Look:"));
268
        mLookNameLabel = new Label(this, "");
269
    }
270
271
    if (serverFeatures->haveCreateCharGender())
272
    {
273
        const int forceGender = features.getIntValue("forceCharGender");
274
        if (forceGender == -1)
275
        {
276
            const int size = config.getIntValue("fontSize");
277
            mGenderStrip = new TabStrip(this,
278
                "gender_" + getWindowName(),
279
                size + 16,
280
                0);
281
            mGenderStrip->setPressFirst(false);
282
            mGenderStrip->addActionListener(this);
283
            mGenderStrip->setActionEventId("gender_");
284
            // TRANSLATORS: one char size female character gender
285
            mGenderStrip->addButton(_("F"), "f", false);
286
            if (features.getIntValue("forceAccountGender") == -1)
287
            {
288
                if (serverFeatures->haveCharHiddenGender())
289
                {
290
                    // TRANSLATORS: one char size male character gender
291
                    mGenderStrip->addButton(_("M"), "m", true);
292
                    // TRANSLATORS: one char size hidden character gender
293
                    mGenderStrip->addButton(_("H"), "h", false);
294
                }
295
                else
296
                {
297
                    // TRANSLATORS: one char size male character gender
298
                    mGenderStrip->addButton(_("M"), "m", false);
299
                    // TRANSLATORS: one char size unknown character gender
300
                    mGenderStrip->addButton(_("U"), "u", true);
301
                }
302
            }
303
            else
304
            {
305
                // TRANSLATORS: one char size male character gender
306
                mGenderStrip->addButton(_("M"), "m", true);
307
                if (serverFeatures->haveCharHiddenGender())
308
                {
309
                    // TRANSLATORS: one char size hidden character gender
310
                    mGenderStrip->addButton(_("H"), "h", false);
311
                }
312
            }
313
314
            mGenderStrip->setVisible(Visible_true);
315
            add(mGenderStrip);
316
317
            mGenderStrip->setPosition(385, 130);
318
            mGenderStrip->setWidth(500);
319
            mGenderStrip->setHeight(50);
320
        }
321
        else
322
        {
323
            mGender = Being::intToGender(CAST_U8(forceGender));
324
            mPlayer->setGender(mGender);
325
        }
326
    }
327
328
    mPlayerBox->setWidth(74);
329
330
    mNameField->setActionEventId("create");
331
    mNameField->addActionListener(this);
332
333
    mPlayerBox->setDimension(Rect(360, 0, 110, 90));
334
    mActionButton->setPosition(385, 100);
335
    mRotateButton->setPosition(415, 100);
336
337
    mNameLabel->setPosition(mPadding, 2);
338
    mNameField->setDimension(Rect(60, 2,
339
        300, mNameField->getHeight()));
340
341
    const uint32_t labelPadding = getOption("labelPadding", 2);
342
    const uint32_t leftX = 120 + mPadding;
343
    const uint32_t rightX = 300 + mPadding;
344
    const uint32_t labelX = mPadding;
345
    uint32_t nameX = leftX + labelPadding;
346
    uint32_t y = 30;
347
    if (mPrevHairColorButton != nullptr)
348
        nameX += mPrevHairColorButton->getWidth();
349
    else if (mPrevHairStyleButton != nullptr)
350
        nameX += mPrevHairStyleButton->getWidth();
351
    else if (mPrevLookButton != nullptr)
352
        nameX += mPrevLookButton->getWidth();
353
    else if (mPrevRaceButton != nullptr)
354
        nameX += mPrevRaceButton->getWidth();
355
356
    if (maxHairColor > minHairColor)
357
    {
358
        mPrevHairColorButton->setPosition(leftX, y);
359
        mNextHairColorButton->setPosition(rightX, y);
360
        y += 5;
361
        mHairColorLabel->setPosition(labelX, y);
362
        mHairColorNameLabel->setPosition(nameX, y);
363
        y += 24;
364
    }
365
    if (maxHairStyle > minHairStyle)
366
    {
367
        mPrevHairStyleButton->setPosition(leftX, y);
368
        mNextHairStyleButton->setPosition(rightX, y);
369
        y += 5;
370
        mHairStyleLabel->setPosition(labelX, y);
371
        mHairStyleNameLabel->setPosition(nameX, y);
372
        y += 24;
373
    }
374
375
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
376
    {
377
        if (mPrevLookButton != nullptr)
378
            mPrevLookButton->setPosition(leftX, y);
379
        if (mNextLookButton != nullptr)
380
            mNextLookButton->setPosition(rightX, y);
381
        y += 5;
382
        if (mLookLabel != nullptr)
383
            mLookLabel->setPosition(labelX, y);
384
        if (mLookNameLabel != nullptr)
385
            mLookNameLabel->setPosition(nameX, y);  // 93
386
        y += 24;
387
    }
388
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
389
    {
390
        if (mPrevRaceButton != nullptr)
391
            mPrevRaceButton->setPosition(leftX, y);
392
        if (mNextRaceButton != nullptr)
393
            mNextRaceButton->setPosition(rightX, y);
394
        y += 5;
395
        if (mRaceLabel != nullptr)
396
            mRaceLabel->setPosition(labelX, y);
397
        if (mRaceNameLabel != nullptr)
398
            mRaceNameLabel->setPosition(nameX, y);
399
    }
400
    mMaxY = y + 29 + getTitlePadding();
401
402
    updateSliders();
403
    setButtonsPosition(w, h);
404
405
    add(mPlayerBox);
406
    add(mNameField);
407
    add(mNameLabel);
408
409
    if (maxHairColor > minHairColor)
410
    {
411
        add(mNextHairColorButton);
412
        add(mPrevHairColorButton);
413
        add(mHairColorLabel);
414
        add(mHairColorNameLabel);
415
    }
416
417
    if (maxHairStyle > minHairStyle)
418
    {
419
        add(mNextHairStyleButton);
420
        add(mPrevHairStyleButton);
421
        add(mHairStyleLabel);
422
        add(mHairStyleNameLabel);
423
    }
424
    add(mActionButton);
425
    add(mRotateButton);
426
427
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
428
    {
429
        add(mNextLookButton);
430
        add(mPrevLookButton);
431
        add(mLookLabel);
432
        add(mLookNameLabel);
433
    }
434
435
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
436
    {
437
        add(mNextRaceButton);
438
        add(mPrevRaceButton);
439
        add(mRaceLabel);
440
        add(mRaceNameLabel);
441
    }
442
443
    add(mAttributesLeft);
444
    add(mCreateButton);
445
    add(mCancelButton);
446
447
    center();
448
    setVisible(Visible_true);
449
    mNameField->requestFocus();
450
451
    updateHair();
452
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
453
        updateRace();
454
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
455
        updateLook();
456
    updatePlayer();
457
458
    addKeyListener(this);
459
}
460
461
CharCreateDialog::~CharCreateDialog()
462
{
463
    delete2(mPlayer)
464
465
    if (charServerHandler != nullptr)
466
        charServerHandler->setCharCreateDialog(nullptr);
467
}
468
469
void CharCreateDialog::action(const ActionEvent &event)
470
{
471
    const std::string &id = event.getId();
472
    if (id == "create")
473
    {
474
        if (getName().length() >= 4)
475
        {
476
            // Attempt to create the character
477
            mCreateButton->setEnabled(false);
478
479
            STD_VECTOR<int> atts;
480
            const size_t sz = mAttributeSlider.size();
481
            for (size_t i = 0; i < sz; i++)
482
            {
483
                atts.push_back(CAST_S32(
484
                    mAttributeSlider[i]->getValue()));
485
            }
486
            for (size_t i = sz; i < 6; i ++)
487
                atts.push_back(1);
488
489
            const int characterSlot = mSlot;
490
491
            charServerHandler->newCharacter(getName(),
492
                characterSlot,
493
                mGender,
494
                mHairStyle,
495
                mHairColor,
496
                CAST_U8(mRace),
497
                CAST_U8(mLook),
498
                atts);
499
        }
500
        else
501
        {
502
            CREATEWIDGET(OkDialog,
503
                // TRANSLATORS: char creation error
504
                _("Error"),
505
                // TRANSLATORS: char creation error
506
                _("Your name needs to be at least 4 characters."),
507
                // TRANSLATORS: ok dialog button
508
                _("OK"),
509
                DialogType::ERROR,
510
                Modal_true,
511
                ShowCenter_true,
512
                nullptr,
513
                260);
514
        }
515
    }
516
    else if (id == "cancel")
517
    {
518
        scheduleDelete();
519
    }
520
    else if (id == "nextcolor")
521
    {
522
        mHairColor ++;
523
        updateHair();
524
    }
525
    else if (id == "prevcolor")
526
    {
527
        mHairColor --;
528
        updateHair();
529
    }
530
    else if (id == "nextstyle")
531
    {
532
        mHairStyle ++;
533
        updateHair();
534
    }
535
    else if (id == "prevstyle")
536
    {
537
        mHairStyle --;
538
        updateHair();
539
    }
540
    else if (id == "nextrace")
541
    {
542
        mRace ++;
543
        updateRace();
544
    }
545
    else if (id == "prevrace")
546
    {
547
        mRace --;
548
        updateRace();
549
    }
550
    else if (id == "nextlook")
551
    {
552
        mLook ++;
553
        updateLook();
554
    }
555
    else if (id == "prevlook")
556
    {
557
        mLook --;
558
        updateLook();
559
    }
560
    else if (id == "statslider")
561
    {
562
        updateSliders();
563
    }
564
    else if (id == "action")
565
    {
566
        mAction ++;
567
        if (mAction >= 5)
568
            mAction = 0;
569
        updatePlayer();
570
    }
571
    else if (id == "rotate")
572
    {
573
        mDirection ++;
574
        if (mDirection >= 4)
575
            mDirection = 0;
576
        updatePlayer();
577
    }
578
    else if (id == "gender_m")
579
    {
580
        mGender = Gender::MALE;
581
        mPlayer->setGender(Gender::MALE);
582
    }
583
    else if (id == "gender_f")
584
    {
585
        mGender = Gender::FEMALE;
586
        mPlayer->setGender(Gender::FEMALE);
587
    }
588
    else if (id == "gender_u")
589
    {
590
        mGender = Gender::UNSPECIFIED;
591
        mPlayer->setGender(mDefaultGender);
592
    }
593
    else if (id == "gender_h")
594
    {
595
        mGender = Gender::HIDDEN;
596
        mPlayer->setGender(Gender::HIDDEN);
597
    }
598
}
599
600
std::string CharCreateDialog::getName() const
601
{
602
    std::string name = mNameField->getText();
603
    trim(name);
604
    return name;
605
}
606
607
void CharCreateDialog::updateSliders()
608
{
609
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
610
    {
611
        // Update captions
612
        mAttributeValue[i]->setCaption(
613
                toString(CAST_S32(mAttributeSlider[i]->getValue())));
614
        mAttributeValue[i]->adjustSize();
615
    }
616
617
    // Update distributed points
618
    const int pointsLeft = mMaxPoints - getDistributedPoints();
619
    if (pointsLeft == 0)
620
    {
621
        // TRANSLATORS: char create dialog label
622
        mAttributesLeft->setCaption(_("Character stats OK"));
623
        mCreateButton->setEnabled(true);
624
    }
625
    else
626
    {
627
        mCreateButton->setEnabled(false);
628
        if (pointsLeft > 0)
629
        {
630
            mAttributesLeft->setCaption(
631
                // TRANSLATORS: char create dialog label
632
                strprintf(_("Please distribute %d points"), pointsLeft));
633
        }
634
        else
635
        {
636
            mAttributesLeft->setCaption(
637
                // TRANSLATORS: char create dialog label
638
                strprintf(_("Please remove %d points"), -pointsLeft));
639
        }
640
    }
641
642
    mAttributesLeft->adjustSize();
643
}
644
645
void CharCreateDialog::unlock()
646
{
647
    mCreateButton->setEnabled(true);
648
}
649
650
int CharCreateDialog::getDistributedPoints() const
651
{
652
    unsigned int points = 0;
653
654
    for (size_t i = 0, sz = mAttributeSlider.size(); i < sz; i++)
655
        points += CAST_U32(mAttributeSlider[i]->getValue());
656
    return CAST_S32(points);
657
}
658
659
void CharCreateDialog::setAttributes(const StringVect &labels,
660
                                     int available,
661
                                     const int min, const int max)
662
{
663
    size_t sz;
664
665
    if (min == max || available == 0)
666
    {
667
        sz = 0U;
668
        available = 0;
669
    }
670
    else
671
    {
672
        sz = labels.size();
673
    }
674
675
    mMaxPoints = available;
676
677
    for (size_t i = 0; i < mAttributeLabel.size(); i++)
678
    {
679
        remove(mAttributeLabel[i]);
680
        delete2(mAttributeLabel[i])
681
        remove(mAttributeSlider[i]);
682
        delete2(mAttributeSlider[i])
683
        remove(mAttributeValue[i]);
684
        delete2(mAttributeValue[i])
685
    }
686
687
    mAttributeLabel.resize(sz);
688
    mAttributeSlider.resize(sz);
689
    mAttributeValue.resize(sz);
690
691
    const uint32_t w = 480;
692
    uint32_t h = 350;
693
    uint32_t y = 89;
694
    if (serverFeatures->haveLookSelection() && mMinLook < mMaxLook)
695
        y += 29;
696
    if (serverFeatures->haveRaceSelection() && mMinRace < mMaxRace)
697
        y += 29;
698
699
    for (size_t i = 0; i < sz; i++)
700
    {
701
        mAttributeLabel[i] = new Label(this, labels[i]);
702
        mAttributeLabel[i]->setWidth(70);
703
        mAttributeLabel[i]->setPosition(mPadding,
704
            y + CAST_S32(i * 24));
705
        mAttributeLabel[i]->adjustSize();
706
        add(mAttributeLabel[i]);
707
708
        mAttributeSlider[i] = new Slider(this, min, max, 1.0);
709
        mAttributeSlider[i]->setDimension(Rect(140 + mPadding,
710
            y + CAST_S32(i * 24),
711
            150,
712
            12));
713
        mAttributeSlider[i]->setActionEventId("statslider");
714
        mAttributeSlider[i]->addActionListener(this);
715
        add(mAttributeSlider[i]);
716
717
        mAttributeValue[i] = new Label(this, toString(min));
718
        mAttributeValue[i]->setPosition(295 + mPadding,
719
            y + CAST_S32(i * 24));
720
        add(mAttributeValue[i]);
721
    }
722
723
    updateSliders();
724
    if (available == 0)
725
    {
726
        mAttributesLeft->setVisible(Visible_false);
727
        h = y;
728
    }
729
    else
730
    {
731
        h = y +
732
            CAST_S32(sz) * 24 +
733
            mAttributesLeft->getHeight() +
734
            getPadding();
735
    }
736
    if (serverFeatures->haveCreateCharGender() &&
737
        features.getIntValue("forceCharGender") == -1 &&
738
        y < 160)
739
    {
740
        if (h < 160)
741
            h = 160;
742
    }
743
    if (h < mMaxY)
744
        h = mMaxY;
745
    if (serverFeatures->haveCreateCharGender())
746
    {
747
        const int forceGender = features.getIntValue("forceCharGender");
748
        if (forceGender == -1 && h < 180)
749
            h = 180;
750
        else if (h < 120)
751
            h = 120;
752
    }
753
    h += mCreateButton->getHeight();
754
755
    setContentSize(w, h);
756
    setButtonsPosition(w, h);
757
}
758
759
void CharCreateDialog::setDefaultGender(const GenderT gender)
760
{
761
    if (features.getIntValue("forceCharGender") != -1)
762
        return;
763
764
    mDefaultGender = gender;
765
    mPlayer->setGender(gender);
766
}
767
768
void CharCreateDialog::updateHair()
769
{
770
    if (mHairStyle <= 0)
771
        mHairStyle = ItemDB::getNumOfHairstyles() - 1;
772
    else
773
        mHairStyle %= ItemDB::getNumOfHairstyles();
774
    if (mHairStyle < CAST_S32(minHairStyle)
775
        || mHairStyle > CAST_S32(maxHairStyle))
776
    {
777
        mHairStyle = minHairStyle;
778
    }
779
    const ItemInfo &item = ItemDB::get(-mHairStyle);
780
    if (mHairStyleNameLabel != nullptr)
781
    {
782
        mHairStyleNameLabel->setCaption(item.getName());
783
        mHairStyleNameLabel->resizeTo(150, 150);
784
    }
785
786
    if (ColorDB::getHairSize() != 0)
787
        mHairColor %= ColorDB::getHairSize();
788
    else
789
        mHairColor = 0;
790
    if (mHairColor < 0)
791
        mHairColor += ColorDB::getHairSize();
792
    if (mHairColor < CAST_S32(minHairColor)
793
        || mHairColor > CAST_S32(maxHairColor))
794
    {
795
        mHairColor = minHairColor;
796
    }
797
    if (mHairColorNameLabel != nullptr)
798
    {
799
        mHairColorNameLabel->setCaption(ColorDB::getHairColorName(
800
            fromInt(mHairColor, ItemColor)));
801
        mHairColorNameLabel->resizeTo(150, 150);
802
    }
803
804
    mPlayer->setSpriteColor(charServerHandler->hairSprite(),
805
        mHairStyle * -1,
806
        item.getDyeColorsString(fromInt(mHairColor, ItemColor)));
807
    updatePlayer();
808
}
809
810
void CharCreateDialog::updateRace()
811
{
812
    if (mRace < mMinRace)
813
        mRace = mMaxRace;
814
    else if (mRace > mMaxRace)
815
        mRace = mMinRace;
816
817
    updateLook();
818
}
819
820
void CharCreateDialog::updateLook()
821
{
822
    const ItemInfo &item = ItemDB::get(-100 - mRace);
823
    const int sz = item.getColorsSize();
824
    if (sz > 0 && serverFeatures->haveLookSelection())
825
    {
826
        if (mLook < 0)
827
            mLook = sz - 1;
828
        if (mLook > mMaxLook)
829
            mLook = mMinLook;
830
        if (mLook >= sz)
831
            mLook = mMinLook;
832
    }
833
    else
834
    {
835
        mLook = 0;
836
    }
837
    mPlayer->setSubtype(fromInt(mRace, BeingTypeId),
838
        CAST_U8(mLook));
839
    if (mRaceNameLabel != nullptr)
840
    {
841
        mRaceNameLabel->setCaption(item.getName());
842
        mRaceNameLabel->resizeTo(150, 150);
843
    }
844
    if (mLookNameLabel != nullptr)
845
    {
846
        mLookNameLabel->setCaption(item.getColorName(
847
            fromInt(mLook, ItemColor)));
848
        mLookNameLabel->resizeTo(150, 150);
849
    }
850
}
851
852
void CharCreateDialog::logic()
853
{
854
    BLOCK_START("CharCreateDialog::logic")
855
    if (mPlayer != nullptr)
856
        mPlayer->logic();
857
    BLOCK_END("CharCreateDialog::logic")
858
}
859
860
void CharCreateDialog::updatePlayer()
861
{
862
    if (mPlayer != nullptr)
863
    {
864
        mPlayer->setDirection(directions[mDirection]);
865
        mPlayer->setAction(actions[mAction], 0);
866
    }
867
}
868
869
void CharCreateDialog::keyPressed(KeyEvent &event)
870
{
871
    const InputActionT actionId = event.getActionId();
872
    PRAGMA45(GCC diagnostic push)
873
    PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
874
    switch (actionId)
875
    {
876
        case InputAction::GUI_CANCEL:
877
            event.consume();
878
            action(ActionEvent(mCancelButton,
879
                mCancelButton->getActionEventId()));
880
            break;
881
882
        default:
883
            break;
884
    }
885
    PRAGMA45(GCC diagnostic pop)
886
}
887
888
void CharCreateDialog::setButtonsPosition(const int w, const int h)
889
{
890
    const int h2 = h - 5 - mCancelButton->getHeight();
891
    if (mainGraphics->getHeight() < 480)
892
    {
893
        if (mMaxPoints != 0)
894
        {
895
            mCreateButton->setPosition(337, 160);
896
            mCancelButton->setPosition(337 + mCreateButton->getWidth(), 160);
897
        }
898
        else
899
        {
900
            mCancelButton->setPosition(
901
                w / 2,
902
                160);
903
            mCreateButton->setPosition(
904
                mCancelButton->getX() - 5 - mCreateButton->getWidth(),
905
                160);
906
        }
907
    }
908
    else
909
    {
910
        mCancelButton->setPosition(
911
            w / 2,
912
            h2);
913
        mCreateButton->setPosition(
914
            mCancelButton->getX() - 5 - mCreateButton->getWidth(),
915
            h2);
916
    }
917
    mAttributesLeft->setPosition(15, h2 - mAttributesLeft->getHeight());
918

3
}