View difference between Paste ID: Bf4Evtih and KVz4y8b4
SHOW: | | - or go back to the newest paste.
1
// ==UserScript==
2
// @name        keyboard controls
3
// @namespace   majsoul_script
4
// @version     1.0
5
// @author      anon
6
// @match        https://www.majsoul.com/*
7
// @match        https://game.maj-soul.com/*
8
// @match        https://majsoul.union-game.com/
9
// @match        https://game.mahjongsoul.com/
10
// @match        https://mahjongsoul.game.yo-star.com/
11
// @description   RTFM
12
// ==/UserScript==
13
// v3
14
// get keycodes here: https://keycode.info/
15
// skip and discard hotkeys will also press the Confirm button at the end of round/game
16
17
18
// planned:
19
// selector for multi-wait chi calls
20
21
// maybe:
22
// tsumogiri + cancel on same button? might be conflicts such as tenpai state
23
// correctly switch selected tile after calling if tile moved
24
// allow skipping of quest/reward screen
25
26
27
// If CONFIRM_DISCARDS is false tile hotkeys will discard immediately.
28
var CONFIRM_DISCARDS = false;
29
// show the hotkeys underneath the tiles.
30
var SHOW_TILE_HOTKEYS = true;
31
//                   1   2   3   4   5   6   7   8   9   0    -    =  bksp |
32
var TILE_HOTKEYS = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 189, 187, 8, 220];
33
// some may not display correctly, override below:
34
var TILE_DISP = ['', '', '', '', '', '', '', '', '', '', '', '=', '←', '\\'];
35
var HOTKEYS = {
36
    // skip and discard hotkeys will also press the Confirm button at the end of round/game
37
    'left': 37, // left arrow
38
    'right': 39, // right arrow
39
    'discard': 13, // enter
40
    'tsumogiri': 84, // t
41
    'skip': 83, // s
42
    'pon': 80, // p
43
    'chi': 67, // c
44
    'kan': 75, // k
45
    'win': 87, // w
46
    'riichi': 82, // r
47
    'pei': 78, // n
48
    'nineterminalsabort': 188, // ,
49
    'autowin': 72, // h
50
    'nocall': 70, // f
51
    'autogiri': 68, // d
52
}
53
// NUMPAD KEYS:        7    8    9    4    5    6   1   2   3   0    .    +
54
var EMOJI_HOTKEYS = [103, 104, 105, 100, 101, 102, 97, 98, 99, 96, 110, 107];
55
//////////////////////////////////////////////
56
//////////////////////////////////////////////
57
//////////////////////////////////////////////
58
var waitkbmod = setInterval(() => {
59
    try {
60
        uiscript.UI_DesktopInfo.Inst.block_emo
61
        view.ViewPlayer_Me.Inst.hand
62
63
        window.onkeydown = function(e) {
64
            // should enable spamming while key is held down (might be system/browser dependant)
65
            var key = e.keyCode ? e.keyCode : e.which;
66
            switch (key) {
67
                case HOTKEYS.left:
68
                    // move 1 tile left
69
                    move_left();
70
                    break;
71
                case HOTKEYS.right:
72
                    // move 1 tile right
73
                    move_right();
74
                    break;
75
            }
76
        }
77
        window.onkeyup = function(e) {
78
            var key = e.keyCode ? e.keyCode : e.which;
79
            switch (key) {
80
                case HOTKEYS.discard:
81
                    discardTile(selectedTile);
82
                    pressConfirm();
83
                    break;
84
                case HOTKEYS.tsumogiri:
85
                    discardTile(view.ViewPlayer_Me.Inst.hand.length - 1);
86
                    break;
87
                case HOTKEYS.skip:
88
                    callOperation('btn_cancel')
89
                    pressConfirm();
90
                    break;
91
                case HOTKEYS.pon:
92
                    callOperation('btn_peng')
93
                    break;
94
                case HOTKEYS.chi:
95
                    callOperation('btn_chi')
96
                    // if there are multiple, check this._data.chi.length > 1, see i.prototype.onBtn_Chi
97
                    break;
98
                case HOTKEYS.kan:
99
                    callOperation('btn_gang')
100
                    break;
101
                case HOTKEYS.win:
102
                    callOperation('btn_hu')
103
                    callOperation('btn_zimo')
104
                    break;
105
                case HOTKEYS.riichi:
106
                    callOperation('btn_lizhi')
107
                    break;
108
                case HOTKEYS.pei:
109
                    callOperation('btn_babei')
110
                    break;
111
                case HOTKEYS.nineterminalsabort:
112
                    callOperation('btn_jiuzhongjiupai')
113
                    break;
114
                case HOTKEYS.autowin:
115
                    toggleAuto('btn_autohu')
116
                    break;
117
                case HOTKEYS.nocall:
118
                    toggleAuto('btn_autonoming')
119
                    break;
120
                case HOTKEYS.autogiri:
121
                    toggleAuto('btn_automoqie')
122
                    break;
123
            }
124
            // send emojis
125
            if (EMOJI_HOTKEYS.includes(key)) {
126
                sendEmoji(EMOJI_HOTKEYS.indexOf(key));
127
            }
128
            // choose tile directly
129
            if (TILE_HOTKEYS.includes(key)) {
130
                var tile = TILE_HOTKEYS.indexOf(key);
131
                if (tile < view.ViewPlayer_Me.Inst.hand.length) {
132
                    if (CONFIRM_DISCARDS)
133
                        selectTile(tile);
134
                    else
135
                        discardTile(tile);
136
137
                }
138
            }
139
140
        }
141
142
        function toggleAuto(op) {
143
            uiscript.UI_DesktopInfo.Inst._container_fun.getChildByName(op)._clickHandler.method()
144
        }
145
146
        function discardTile(index) {
147
            view.ViewPlayer_Me.Inst._choose_pai = view.ViewPlayer_Me.Inst.hand[index];
148
            view.ViewPlayer_Me.Inst.can_discard && view.ViewPlayer_Me.Inst._choose_pai.valid && (view.ViewPlayer_Me.Inst.DoDiscardTile(),
149
                view.ViewPlayer_Me.Inst.resetMouseState())
150
        }
151
152
        function pressConfirm() {
153
            if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_liuju && uiscript.UIMgr.Inst._ui_liuju._enable)
154
                uiscript.UIMgr.Inst._ui_liuju.onBtnConfirm();
155
            if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_gameend && uiscript.UIMgr.Inst._ui_gameend._enable)
156
                uiscript.UIMgr.Inst._ui_gameend.onConfirm();
157
            if (uiscript.UI_Huleshow.Inst && uiscript.UI_Huleshow.Inst._enable)
158
                uiscript.UI_Huleshow.Inst.onBtnConfirm();
159
            if (uiscript.UI_ScoreChange.Inst && uiscript.UI_ScoreChange.Inst._enable)
160
                uiscript.UI_ScoreChange.Inst.onBtnConfirm();
161
            if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_win && uiscript.UIMgr.Inst._ui_win._enable)
162
                uiscript.UIMgr.Inst._ui_win.onConfirm();
163
        }
164
165
        function sendEmoji(index) {
166
            var validc = 0;
167
            if (!uiscript.UI_DesktopInfo.Inst.block_emo.allgray)
168
                uiscript.UI_DesktopInfo.Inst.block_emo.scrollview._container_items._childs.some((e, i) => {
169
                    if (e.getChildByName('btn')._clickHandler) {
170
                        if (validc == index) {
171
                            uiscript.UI_DesktopInfo.Inst.block_emo.muted = true;
172
                            uiscript.UI_DesktopInfo.Inst.block_emo.scrollview._container_items._childs[i].getChildByName('btn')._clickHandler.method()
173
                            return true;
174
                        }
175
                        validc++;
176
                    }
177
                });
178
        }
179
        uiscript.UI_DesktopInfo.Inst.block_emo.__proto__.switchShow = (function() {
180
            var cacheF = uiscript.UI_DesktopInfo.Inst.block_emo.__proto__.switchShow;
181
            return function() {
182
                if (this.muted)
183
                    this.muted = false;
184
                else
185
                    return cacheF.apply(this, arguments);
186
            };
187
        })();
188
189
        var selectedTile = 0;
190
191
        function selectTile(index) {
192
            var n = 0,
193
                a = 0;
194
            Laya.Browser.width / 1920 < Laya.Browser.height / 1080 ? a = (Laya.Browser.height - Laya.Browser.width / 1920 * 1080) / 2 : n = (Laya.Browser.width - Laya.Browser.height / 1080 * 1920) / 2;
195
            Laya.MouseManager.instance.mouseX = ((index * view.ViewPlayer_Me.Inst.handwidth + view.ViewPlayer_Me.Inst.handorigin_x) - view.ViewPlayer_Me.Inst.screen_left) / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left) * (Laya.Browser.width - 2 * n);
196
            Laya.MouseManager.instance.mouseY = (-view.ViewPlayer_Me.Inst.screen_top) / (view.ViewPlayer_Me.Inst.screen_bottom - view.ViewPlayer_Me.Inst.screen_top) * (Laya.Browser.height - 2 * a)
197
            selectedTile = index;
198
        }
199
200
        function move_left() {
201
            selectedTile = (selectedTile + view.ViewPlayer_Me.Inst.hand.length - 1) % view.ViewPlayer_Me.Inst.hand.length;
202
            while (!view.ViewPlayer_Me.Inst.hand[selectedTile].valid) {
203
                selectedTile = (selectedTile + view.ViewPlayer_Me.Inst.hand.length - 1) % view.ViewPlayer_Me.Inst.hand.length;
204
            }
205
            selectTile(selectedTile);
206
        }
207
208
        function move_right() {
209
            selectedTile = (selectedTile + 1) % view.ViewPlayer_Me.Inst.hand.length;
210
            while (!view.ViewPlayer_Me.Inst.hand[selectedTile].valid) {
211
                selectedTile = (selectedTile + 1) % view.ViewPlayer_Me.Inst.hand.length;
212
            }
213
            selectTile(selectedTile);
214
        }
215
216
        function callOperation(opname) {
217
            this.GameMgr.Inst._pre_mouse_point = new Laya.Point(1, 1);
218
            if (uiscript.UI_LiQiZiMo.Inst.enable && uiscript.UI_LiQiZiMo.Inst._oplist.includes(opname)) {
219
                uiscript.UI_LiQiZiMo.Inst.onClickOpBtn(opname)
220
            } else if (uiscript.UI_ChiPengHu.Inst.enable && uiscript.UI_ChiPengHu.Inst._oplist.includes(opname)) {
221
                uiscript.UI_ChiPengHu.Inst.onClickOpBtn(opname)
222
            }
223
        }
224
225
        var keycss = `
226
:root {
227
	--keySize: 2.5vw;
228
	--keySizeH: 2.5vh;
229
}
230
.key__button {
231
  box-sizing: border-box;
232
  line-height: min(var(--keySize),calc(1.778*var(--keySizeH)));
233
  font-size: calc(.8*min(var(--keySize),calc(1.778*var(--keySizeH))));
234
  text-align: center;
235
  width: var(--keySize);
236
  color: #555;
237
  height: var(--keySize);
238
  max-width: calc(1.778*var(--keySizeH));
239
  max-height: calc(1.778*var(--keySizeH));
240
  border-color: #f2f2f2;
241
  border-style: solid;
242
  text-shadow: 0 0.5px 1px #777, 0 2px 6px #f2f2f2;
243
  border-width: 1px;
244
  border-radius: calc(.25*min(var(--keySize),calc(1.778*var(--keySizeH))));
245
  background: -webkit-linear-gradient(top, #f9f9f9 0%, #D2D2D2 80%, #c0c0c0 100%);
246
  font-family: sans-serif;
247
  display: inline-block;
248
  transition: box-shadow 0.3s ease, transform 0.15s ease;
249
  box-shadow: 0 0 1px #888,0 1px 0 #fff, 0 6px 0 #C0C0C0, 0 8px 17px rgba(#444, 0.4), 2px 1px 4px rgba(#444, 0.25), -2px 1px 4px rgba(#444, 0.25), 0 9px 16px rgba(#444, 0.1);
250
}
251
#tileLabels {
252
  display: flex;
253
  justify-content: space-around;
254
  align-items: flex-end;
255
  height: 100%;
256
  width: var(--labelsWidth);
257
  margin-left: var(--offsetLeft);
258
  pointer-events: none;
259
}
260
#tileWrapper
261
{
262
    width: 100vw; 
263
    height: 56.25vw; /* 100/56.25 = 1.778 */
264
    max-height: 100vh;
265
    max-width: 177.78vh; /* 16/9 = 1.778 */
266
    margin: auto;
267
    position: absolute;
268
    top:0;bottom:0; /* vertical center */
269
    left:0;right:0; /* horizontal center */
270
	pointer-events: none;
271
}
272
	`,
273
            head = document.head || document.getElementsByTagName('head')[0],
274
            style = document.getElementById('tileStyle') || document.createElement("STYLE");
275
        style.setAttribute('id', 'tileStyle');
276
        style.innerHTML = '';
277
        style.type = 'text/css';
278
        head.appendChild(style);
279
        var n = 0,
280
            a = 0;
281
282
        Laya.Browser.width / 1920 < Laya.Browser.height / 1080 ? a = (Laya.Browser.height - Laya.Browser.width / 1920 * 1080) / 2 : n = (Laya.Browser.width - Laya.Browser.height / 1080 * 1920) / 2;
283
        var x = (view.ViewPlayer_Me.Inst.handorigin_x - view.ViewPlayer_Me.Inst.screen_left - view.ViewPlayer_Me.Inst.handwidth / 2) / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left),
284
            w = view.ViewPlayer_Me.Inst.handwidth * 14 / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left);
285
        var keycssvars = ':root {--offsetLeft: ' + x * 100 + '%; --labelsWidth:' + w * 100 + '%; --maxWidth:' + w * 100 * 16 / 9 + 'vh}';
286
        style.appendChild(document.createTextNode(keycssvars));
287
        style.appendChild(document.createTextNode(keycss));
288
289
290
        var tileWrapper = document.getElementById('tileWrapper') || document.createElement("DIV");
291
        var tileLabels = document.getElementById('tileLabels') || document.createElement("DIV");
292
        tileWrapper.innerHTML = '';
293
        tileWrapper.setAttribute('id', 'tileWrapper')
294
        tileLabels.innerHTML = '';
295
        tileLabels.setAttribute('id', 'tileLabels')
296
        tileWrapper.appendChild(tileLabels);
297
        var TILE_ELEMENTS = [];
298
        TILE_HOTKEYS.forEach((key, i) => {
299
            let kdiv = document.createElement('DIV');
300
            kdiv.setAttribute('class', 'key__button');
301
            if (TILE_DISP[i])
302
                kdiv.innerHTML = TILE_DISP[i];
303
            else {
304
                let chrCode = key - 48 * Math.floor(key / 48);
305
                let chr = String.fromCharCode((96 <= key) ? chrCode : key);
306
                kdiv.innerHTML = chr;
307
            }
308
            tileLabels.appendChild(kdiv);
309
            TILE_ELEMENTS.push(kdiv);
310
        });
311
        document.body.appendChild(tileWrapper);
312
313
        function isInGame() {
314-
            if (isInGame()) {
314+
315
        }
316
        setInterval(() => {
317
            if (isInGame() && SHOW_TILE_HOTKEYS) {
318
                tileLabels.style.display = 'flex';
319
                // hide unneeded hotkeys
320
                TILE_ELEMENTS.forEach((e, i) => {
321
                    if (i < view.ViewPlayer_Me.Inst.hand.length)
322
                        e.style.visibility = 'visible';
323
                    else
324
                        e.style.visibility = 'hidden';
325
                });
326
327
            } else
328
                tileLabels.style.display = 'none';
329
        }, 500);
330
331
        clearInterval(waitkbmod);
332
    } catch (TypeError) {}
333
}, 1000);