GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gamemodifiers.cpp Lines: 1 140 0.7 %
Date: 2021-03-17 Branches: 0 138 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "gamemodifiers.h"
23
24
#include "configuration.h"
25
#include "game.h"
26
#include "settings.h"
27
#include "soundmanager.h"
28
29
#include "being/localplayer.h"
30
31
#include "gui/viewport.h"
32
33
#include "gui/windows/chatwindow.h"
34
#include "gui/windows/okdialog.h"
35
#include "gui/windows/outfitwindow.h"
36
37
#include "gui/widgets/createwidget.h"
38
39
#include "gui/widgets/tabs/chat/chattab.h"
40
41
#include "listeners/gamemodifierlistener.h"
42
43
#include "resources/map/map.h"
44
45
#include "listeners/awaylistener.h"
46
#include "listeners/updatestatuslistener.h"
47
48
#include "utils/gettext.h"
49
50
#include "debug.h"
51
52
#define addModifier(name1, name2, sz, ...) \
53
    const unsigned GameModifiers::m##name1##Size = sz; \
54
    const char *const GameModifiers::m##name1##Strings[] = \
55
    __VA_ARGS__; \
56
    std::string GameModifiers::get##name1##String() \
57
    { \
58
        return gettext(getVarItem(&m##name1##Strings[0], \
59
        CAST_U32(settings.name2), m##name1##Size)); \
60
    }
61
62
#define addModifier2(name1, name2, str, sz, ...) \
63
    const unsigned GameModifiers::m##name1##Size = sz; \
64
    const char *const GameModifiers::m##name1##Strings[] = \
65
    __VA_ARGS__; \
66
    void GameModifiers::change##name1(const bool forward) \
67
    { \
68
        changeMode(&settings.name2, m##name1##Size, str, \
69
            &GameModifiers::get##name1##String, 0, true, forward); \
70
    } \
71
    std::string GameModifiers::get##name1##String() \
72
    { \
73
        return gettext(getVarItem(&m##name1##Strings[0], \
74
        settings.name2, m##name1##Size)); \
75
    }
76
77
#define changeMethod(name1, name2, str) \
78
    void GameModifiers::change##name1(const bool forward) \
79
    { \
80
        changeMode(&settings.name2, m##name1##Size, str, \
81
            &GameModifiers::get##name1##String, 0, true, forward); \
82
    }
83
84
void GameModifiers::init()
85
{
86
    settings.crazyMoveType = config.getIntValue("crazyMoveType");
87
    settings.moveToTargetType = config.getIntValue("moveToTargetType");
88
    settings.followMode = config.getIntValue("followMode");
89
    settings.attackWeaponType = config.getIntValue("attackWeaponType");
90
    settings.attackType = config.getIntValue("attackType");
91
    settings.targetingType = config.getIntValue("targetingType");
92
    settings.quickDropCounter = config.getIntValue("quickDropCounter");
93
    settings.pickUpType = config.getIntValue("pickUpType");
94
    settings.magicAttackType = config.getIntValue("magicAttackType");
95
    settings.pvpAttackType = config.getIntValue("pvpAttackType");
96
    settings.imitationMode = config.getIntValue("imitationMode");
97
    settings.disableGameModifiers = config.getBoolValue(
98
        "disableGameModifiers");
99
    settings.awayMode = false;
100
    settings.mapDrawType = MapType::NORMAL;
101
//    UpdateStatusListener::distributeEvent();
102
}
103
104
void GameModifiers::changeMode(unsigned *restrict const var,
105
                               const unsigned limit,
106
                               const char *restrict const conf,
107
                               std::string (*const func)(),
108
                               const unsigned def,
109
                               const bool save,
110
                               const bool forward)
111
{
112
    if (var == nullptr)
113
        return;
114
115
    if (forward)
116
    {
117
        (*var) ++;
118
        if (*var >= limit)
119
            *var = def;
120
    }
121
    else
122
    {
123
        if (*var == 0U)
124
            *var = limit - 1;
125
        else
126
            (*var) --;
127
    }
128
129
    if (save)
130
        config.setValue(conf, *var);
131
    UpdateStatusListener::distributeEvent();
132
    GameModifierListener::distributeEvent();
133
    const std::string str = (*func)();
134
    if (str.size() > 4)
135
        debugMsg(str.substr(4))
136
}
137
138
const char *GameModifiers::getVarItem(const char *const *const arr,
139
                                      const unsigned index,
140
                                      const unsigned sz)
141
{
142
    if (index < sz)
143
        return arr[index];
144
    return arr[sz];
145
}
146
147
addModifier(MoveType, moveType, 5,
148
{
149
    // TRANSLATORS: move type in status bar
150
    N_("(D) default moves"),
151
    // TRANSLATORS: move type in status bar
152
    N_("(I) invert moves"),
153
    // TRANSLATORS: move type in status bar
154
    N_("(c) moves with some crazy moves"),
155
    // TRANSLATORS: move type in status bar
156
    N_("(C) moves with crazy moves"),
157
    // TRANSLATORS: move type in status bar
158
    N_("(d) double normal + crazy"),
159
    // TRANSLATORS: move type in status bar
160
    N_("(?) unknown move")
161
})
162
163
void GameModifiers::changeMoveType(const bool forward)
164
{
165
    localPlayer->setMoveState(0);
166
    changeMode(&settings.moveType, mMoveTypeSize, "invertMoveDirection",
167
        &GameModifiers::getMoveTypeString, 0, false, forward);
168
}
169
170
const unsigned GameModifiers::mCrazyMoveTypeSize = 11;
171
172
void GameModifiers::changeCrazyMoveType(const bool forward)
173
{
174
    settings.crazyMoveState = 0U;
175
    changeMode(&settings.crazyMoveType, mCrazyMoveTypeSize, "crazyMoveType",
176
        &GameModifiers::getCrazyMoveTypeString, 1, true, forward);
177
}
178
179
std::string GameModifiers::getCrazyMoveTypeString()
180
{
181
    const unsigned int crazyMoveType = settings.crazyMoveType;
182
    if (crazyMoveType < mCrazyMoveTypeSize - 1)
183
    {
184
        // TRANSLATORS: crazy move type in status bar
185
        return strprintf(_("(%u) crazy move number %u"),
186
            crazyMoveType, crazyMoveType);
187
    }
188
    else if (crazyMoveType == mCrazyMoveTypeSize - 1)
189
    {
190
        // TRANSLATORS: crazy move type in status bar
191
        return _("(a) custom crazy move");
192
    }
193
    else
194
    {
195
        // TRANSLATORS: crazy move type in status bar
196
        return _("(?) crazy move");
197
    }
198
}
199
200
addModifier2(MoveToTargetType, moveToTargetType, "moveToTargetType", 13,
201
{
202
    // TRANSLATORS: move to target type in status bar
203
    N_("(0) default moves to target"),
204
    // TRANSLATORS: move to target type in status bar
205
    N_("(1) moves to target in distance 1"),
206
    // TRANSLATORS: move to target type in status bar
207
    N_("(2) moves to target in distance 2"),
208
    // TRANSLATORS: move to target type in status bar
209
    N_("(3) moves to target in distance 3"),
210
    // TRANSLATORS: move to target type in status bar
211
    N_("(4) moves to target in distance 4"),
212
    // TRANSLATORS: move to target type in status bar
213
    N_("(5) moves to target in distance 5"),
214
    // TRANSLATORS: move to target type in status bar
215
    N_("(6) moves to target in distance 6"),
216
    // TRANSLATORS: move to target type in status bar
217
    N_("(7) moves to target in distance 7"),
218
    // TRANSLATORS: move to target type in status bar
219
    N_("(8) moves to target in distance 8"),
220
    // TRANSLATORS: move to target type in status bar
221
    N_("(9) moves to target in distance 9"),
222
    // TRANSLATORS: move to target type in status bar
223
    N_("(A) moves to target in attack range"),
224
    // TRANSLATORS: move to target type in status bar
225
    N_("(a) archer attack range"),
226
    // TRANSLATORS: move to target type in status bar
227
    N_("(B) moves to target in attack range - 1"),
228
    // TRANSLATORS: move to target type in status bar
229
    N_("(?) move to target")
230
})
231
232
addModifier2(FollowMode, followMode, "followMode", 4,
233
{
234
    // TRANSLATORS: folow mode in status bar
235
    N_("(D) default follow"),
236
    // TRANSLATORS: folow mode in status bar
237
    N_("(R) relative follow"),
238
    // TRANSLATORS: folow mode in status bar
239
    N_("(M) mirror follow"),
240
    // TRANSLATORS: folow mode in status bar
241
    N_("(P) pet follow"),
242
    // TRANSLATORS: folow mode in status bar
243
    N_("(?) unknown follow")
244
})
245
246
addModifier2(AttackWeaponType, attackWeaponType, "attackWeaponType", 4,
247
{
248
    // TRANSLATORS: switch attack type in status bar
249
    N_("(?) attack"),
250
    // TRANSLATORS: switch attack type in status bar
251
    N_("(D) default attack"),
252
    // TRANSLATORS: switch attack type in status bar
253
    N_("(s) switch attack without shield"),
254
    // TRANSLATORS: switch attack type in status bar
255
    N_("(S) switch attack with shield"),
256
    // TRANSLATORS: switch attack type in status bar
257
    N_("(?) attack")
258
})
259
260
addModifier2(AttackType, attackType, "attackType", 4,
261
{
262
    // TRANSLATORS: attack type in status bar
263
    N_("(D) default attack"),
264
    // TRANSLATORS: attack type in status bar
265
    N_("(G) go and attack"),
266
    // TRANSLATORS: attack type in status bar
267
    N_("(A) go, attack, pickup"),
268
    // TRANSLATORS: attack type in status bar
269
    N_("(d) without auto attack"),
270
    // TRANSLATORS: attack type in status bar
271
    N_("(?) attack")
272
})
273
274
addModifier2(TargetingType, targetingType, "targetingType", 2,
275
{
276
    // TRANSLATORS: targeting type in status bar
277
    N_("(D) don't switch target"),
278
    // TRANSLATORS: targeting type in status bar
279
    N_("(C) always attack closest"),
280
    // TRANSLATORS: targeting type in status bar
281
    N_("(?) targeting")
282
})
283
284
const unsigned GameModifiers::mQuickDropCounterSize = 31;
285
286
changeMethod(QuickDropCounter, quickDropCounter, "quickDropCounter")
287
288
std::string GameModifiers::getQuickDropCounterString()
289
{
290
    const unsigned int cnt = settings.quickDropCounter;
291
    if (cnt > 9)
292
    {
293
        return strprintf("(%c) drop counter %u", CAST_S8(
294
            'a' + cnt - 10), cnt);
295
    }
296
    return strprintf("(%u) drop counter %u", cnt, cnt);
297
}
298
299
void GameModifiers::setQuickDropCounter(const int n)
300
{
301
    if (n < 1 || n >= CAST_S32(mQuickDropCounterSize))
302
        return;
303
    settings.quickDropCounter = n;
304
    config.setValue("quickDropCounter", n);
305
    UpdateStatusListener::distributeEvent();
306
    GameModifierListener::distributeEvent();
307
}
308
309
addModifier2(PickUpType, pickUpType, "pickUpType", 7,
310
{
311
    // TRANSLATORS: pickup size in status bar
312
    N_("(S) small pick up 1x1 cells"),
313
    // TRANSLATORS: pickup size in status bar
314
    N_("(D) default pick up 2x1 cells"),
315
    // TRANSLATORS: pickup size in status bar
316
    N_("(F) forward pick up 2x3 cells"),
317
    // TRANSLATORS: pickup size in status bar
318
    N_("(3) pick up 3x3 cells"),
319
    // TRANSLATORS: pickup size in status bar
320
    N_("(g) go and pick up in distance 4"),
321
    // TRANSLATORS: pickup size in status bar
322
    N_("(G) go and pick up in distance 8"),
323
    // TRANSLATORS: pickup size in status bar
324
    N_("(A) go and pick up in max distance"),
325
    // TRANSLATORS: pickup size in status bar
326
    N_("(?) pick up")
327
})
328
329
addModifier2(MagicAttackType, magicAttackType, "magicAttackType", 5,
330
{
331
    // TRANSLATORS: magic attack in status bar
332
    N_("(f) use #flar for magic attack"),
333
    // TRANSLATORS: magic attack in status bar
334
    N_("(c) use #chiza for magic attack"),
335
    // TRANSLATORS: magic attack in status bar
336
    N_("(I) use #ingrav for magic attack"),
337
    // TRANSLATORS: magic attack in status bar
338
    N_("(F) use #frillyar for magic attack"),
339
    // TRANSLATORS: magic attack in status bar
340
    N_("(U) use #upmarmu for magic attack"),
341
    // TRANSLATORS: magic attack in status bar
342
    N_("(?) magic attack")
343
})
344
345
addModifier2(PvpAttackType, pvpAttackType, "pvpAttackType", 4,
346
{
347
    // TRANSLATORS: player attack type in status bar
348
    N_("(a) attack all players"),
349
    // TRANSLATORS: player attack type in status bar
350
    N_("(f) attack all except friends"),
351
    // TRANSLATORS: player attack type in status bar
352
    N_("(b) attack bad relations"),
353
    // TRANSLATORS: player attack type in status bar
354
    N_("(d) don't attack players"),
355
    // TRANSLATORS: player attack type in status bar
356
    N_("(?) pvp attack")
357
})
358
359
addModifier2(ImitationMode, imitationMode, "imitationMode", 2,
360
{
361
    // TRANSLATORS: imitation type in status bar
362
    N_("(D) default imitation"),
363
    // TRANSLATORS: imitation type in status bar
364
    N_("(O) outfits imitation"),
365
    // TRANSLATORS: imitation type in status bar
366
    N_("(?) imitation")
367
})
368
369
addModifier(GameModifiers, disableGameModifiers, 2,
370
{
371
    // TRANSLATORS: game modifiers state in status bar
372
    N_("Game modifiers are enabled"),
373
    // TRANSLATORS: game modifiers state in status bar
374
    N_("Game modifiers are disabled"),
375
    // TRANSLATORS: game modifiers state in status bar
376
    N_("Game modifiers are unknown")
377
})
378
379
void GameModifiers::changeGameModifiers(const bool forward A_UNUSED)
380
{
381
    settings.disableGameModifiers = !settings.disableGameModifiers;
382
    config.setValue("disableGameModifiers", settings.disableGameModifiers);
383
    UpdateStatusListener::distributeEvent();
384
    GameModifierListener::distributeEvent();
385
}
386
387
addModifier(MapDrawType, mapDrawType, 7,
388
{
389
    // TRANSLATORS: map view type in status bar
390
    N_("(N) normal map view"),
391
    // TRANSLATORS: map view type in status bar
392
    N_("(D) debug map view"),
393
    // TRANSLATORS: map view type in status bar
394
    N_("(u) ultra map view"),
395
    // TRANSLATORS: map view type in status bar
396
    N_("(U) ultra map view 2"),
397
    // TRANSLATORS: map view type in status bar
398
    N_("(e) empty map view with collision"),
399
    // TRANSLATORS: map view type in status bar
400
    N_("(E) empty map view"),
401
    // TRANSLATORS: map view type in status bar
402
    N_("(b) black & white map view"),
403
    // TRANSLATORS: pickup size in status bar
404
    N_("(?) map view")
405
})
406
407
void GameModifiers::changeMapDrawType(const bool forward A_UNUSED)
408
{
409
    if (viewport != nullptr)
410
        viewport->toggleMapDrawType();
411
}
412
413
addModifier(AwayMode, awayMode, 2,
414
{
415
    // TRANSLATORS: away type in status bar
416
    N_("(O) on keyboard"),
417
    // TRANSLATORS: away type in status bar
418
    N_("(A) away"),
419
    // TRANSLATORS: away type in status bar
420
    N_("(?) away")
421
})
422
423
void GameModifiers::changeAwayMode(const bool forward A_UNUSED)
424
{
425
    if (localPlayer == nullptr)
426
        return;
427
428
    settings.awayMode = !settings.awayMode;
429
    localPlayer->setAfkTime(0);
430
    localPlayer->setHalfAway(false);
431
    localPlayer->updateName();
432
    Game::instance()->updateFrameRate(0);
433
    UpdateStatusListener::distributeEvent();
434
    GameModifierListener::distributeEvent();
435
    if (settings.awayMode)
436
    {
437
        if (chatWindow != nullptr)
438
            chatWindow->clearAwayLog();
439
440
        localPlayer->cancelFollow();
441
        localPlayer->navigateClean();
442
        if (outfitWindow != nullptr)
443
            outfitWindow->wearAwayOutfit();
444
        OkDialog *const dialog = CREATEWIDGETR(OkDialog,
445
            // TRANSLATORS: away message box header
446
            _("Away"),
447
            serverConfig.getValue("afkMessage", "I am away from keyboard."),
448
            // TRANSLATORS: ok dialog button
449
            _("OK"),
450
            DialogType::SILENCE,
451
            Modal_true,
452
            ShowCenter_false,
453
            nullptr,
454
            260);
455
        localPlayer->setAwayDialog(dialog);
456
        dialog->addActionListener(localPlayer->getAwayListener());
457
        soundManager.volumeOff();
458
        localPlayer->addAfkEffect();
459
    }
460
    else
461
    {
462
        localPlayer->setAwayDialog(nullptr);
463
        soundManager.volumeRestore();
464
        if (chatWindow != nullptr)
465
        {
466
            chatWindow->displayAwayLog();
467
            chatWindow->clearAwayLog();
468
        }
469
        localPlayer->removeAfkEffect();
470
    }
471
}
472
473
addModifier(CameraMode, cameraMode, 2,
474
{
475
    // TRANSLATORS: camera mode in status bar
476
    N_("(G) game camera mode"),
477
    // TRANSLATORS: camera mode in status bar
478
    N_("(F) free camera mode"),
479
    // TRANSLATORS: camera mode in status bar
480
    N_("(?) away")
481
})
482
483
484
void GameModifiers::changeCameraMode(const bool forward A_UNUSED)
485
{
486
    if (viewport != nullptr)
487
        viewport->toggleCameraMode();
488
}
489
490
void GameModifiers::resetModifiers()
491
{
492
    settings.moveType = 0;
493
    settings.crazyMoveType = config.resetIntValue("crazyMoveType");
494
    settings.moveToTargetType = config.resetIntValue("moveToTargetType");
495
    settings.followMode = config.resetIntValue("followMode");
496
    settings.attackWeaponType = config.resetIntValue("attackWeaponType");
497
    settings.attackType = config.resetIntValue("attackType");
498
    settings.magicAttackType = config.resetIntValue("magicAttackType");
499
    settings.pvpAttackType = config.resetIntValue("pvpAttackType");
500
    settings.quickDropCounter = config.resetIntValue("quickDropCounter");
501
    settings.pickUpType = config.resetIntValue("pickUpType");
502
    settings.targetingType = config.resetIntValue("targetingType");
503
    settings.mapDrawType = MapType::NORMAL;
504
    if (viewport != nullptr)
505
    {
506
        if (settings.cameraMode != 0U)
507
            viewport->toggleCameraMode();
508
        Map *const map = viewport->getMap();
509
        if (map != nullptr)
510
            map->setDrawLayersFlags(MapType::NORMAL);
511
    }
512
    settings.imitationMode = config.resetIntValue("imitationMode");
513
    settings.disableGameModifiers = config.resetBoolValue(
514
        "disableGameModifiers");
515
516
    UpdateStatusListener::distributeEvent();
517
    GameModifierListener::distributeEvent();
518
2
}