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

6
}