summaryrefslogtreecommitdiff
path: root/common/accel-union.hpp
blob: 97496e1359601cb057f3bf41f15e545991bc4e34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once

#include "accel-classic.hpp"
#include "accel-jump.hpp"
#include "accel-natural.hpp"
#include "accel-power.hpp"
#include "accel-motivity.hpp"
#include "accel-noaccel.hpp"

namespace rawaccel {

    enum class internal_mode {
        classic_lgcy,
        classic_gain,
        jump_lgcy,
        jump_gain,
        natural_lgcy,
        natural_gain,
        power,
        motivity,
        noaccel
    };

    constexpr internal_mode make_mode(accel_mode m, bool legacy) 
    {
        switch (m) {
        case accel_mode::classic:
            return legacy ? internal_mode::classic_lgcy : internal_mode::classic_gain;
        case accel_mode::jump:
            return legacy ? internal_mode::jump_lgcy : internal_mode::jump_gain;
        case accel_mode::natural:
            return legacy ? internal_mode::natural_lgcy : internal_mode::natural_gain;
        case accel_mode::power:
            return internal_mode::power;
        case accel_mode::motivity:
            return internal_mode::motivity;
        default:
            return internal_mode::noaccel;
        }
    }

    constexpr internal_mode make_mode(const accel_args& args) 
    {
        return make_mode(args.mode, args.legacy);
    }

    template <typename Visitor, typename Variant>
    inline auto visit_accel(Visitor vis, Variant&& var) 
    {
        switch (var.tag) {
        case internal_mode::classic_lgcy: return vis(var.u.classic_l);
        case internal_mode::classic_gain: return vis(var.u.classic_g);
        case internal_mode::jump_lgcy: return vis(var.u.jump_l);
        case internal_mode::jump_gain: return vis(var.u.jump_g);
        case internal_mode::natural_lgcy: return vis(var.u.natural_l);
        case internal_mode::natural_gain: return vis(var.u.natural_g);
        case internal_mode::power:        return vis(var.u.power);
        case internal_mode::motivity:     return vis(var.u.motivity);
        default:                          return vis(var.u.noaccel);
        }
    }

    struct accel_variant {
        si_pair* lookup;

        internal_mode tag = internal_mode::noaccel;

        union union_t {
            classic classic_g;
            classic_legacy classic_l;
            jump jump_g;
            jump_legacy jump_l;
            natural natural_g;
            natural_legacy natural_l;
            power power;
            motivity motivity;
            accel_noaccel noaccel = {};
        } u = {};

        accel_variant(const accel_args& args, si_pair* lut = nullptr) :
            tag(make_mode(args)), lookup(lut)
        {
            visit_accel([&](auto& impl) {
                impl = { args };
            }, *this);

            if (lookup && tag == internal_mode::motivity) {
                u.motivity.fill(lookup);
            }

        }

        double apply(double speed) const 
        {
            if (lookup && tag == internal_mode::motivity) {
                return u.motivity.apply(lookup, speed);
            }

            return visit_accel([=](auto&& impl) {
                return impl(speed);
            }, *this);
        }

        accel_variant() = default;
    };

}