View difference between Paste ID: NbFrEq5g and krs3FXxX
SHOW: | | - or go back to the newest paste.
1
// ==UserScript==
2
// @id             twitch-plays-control@meiguro.com
3
// @name           Twitch Plays Pokémon Touch Controller
4
// @version        0.3.2
5
// @author         Meiguro <meiguro@meiguro.com> http://meiguro.com/
6
// @namespace      https://github.com/Meiguro/twitch-plays-control
7
// @description    Add Touch controls to Twitch Plays Pokemon touch-enabled games.
8
// @include        /^https?://(www|beta)?\.?twitch.tv/twitch_?plays.*$/
9
// @grant          unsafeWindow, GM_addStyle, GM_info
10
// @run-at         document-start
11
// @updateURL      https://raw.githubusercontent.com/Meiguro/twitch-plays-control/master/twitch-plays-control.meta.js
12
// @installURL     https://raw.githubusercontent.com/Meiguro/twitch-plays-control/master/twitch-plays-control.user.js
13
// @downloadURL    https://raw.githubusercontent.com/Meiguro/twitch-plays-control/master/twitch-plays-control.user.js
14
// ==/UserScript==
15
16
/**
17
 *   v0.3.2 CHANGELOG ༼ つ ◕_◕ ༽つ
18
 *
19
 * - Fixed the coordinate range to be 1,1 - 319,239.
20
 *
21
 *   v0.3.1
22
 *
23
 * - Updated to the new 3DS layout. Reset your controller settings if the
24
 *   touch input box is in the wrong location.
25
 *
26
 * - The logic has been separated into components for maintainability. There
27
 *   should be no break in functionality.
28
 *
29
 * Enjoy!
30
 *
31
 * - Meiguro
32
 */
33
34
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
35
/* globals GM_addStyle, GM_info */
36
37
var util2 = require('util2');
38
39
var dd = require('dd');
40
dd.ui = require('dd-ui');
41
42
var Entity = require('entity');
43
var Touch = require('touch');
44
var Chat = require('chat');
45
var Settings = require('settings');
46
var mywindow = require('window');
47
48
require('gm-shims');
49
50
var Control = function(def) {
51
  Entity.call(this, def);
52
  this.config = {};
53
};
54
55
util2.inherit(Control, Entity, Control.prototype);
56
57
Control.DefaultConfig = {
58
  delay: 50,
59
  screen: {
60
    aspect: 1280 / 720,
61
    position: [0.997, 0.977],
62
    scale: 0.392,
63
    size: [320, 240],
64
    barHeight: 30
65
  },
66
  enabled: true,
67
  showBorder: true,
68
  showCoordTooltip: true,
69
  showCross: true,
70
  autoSend: true,
71
  showDroplets: true,
72
  streamDelay: 15,
73
};
74
75
Control.PlayerSelector = '.dynamic-player, .player-container';
76
77
Control.prototype.updateLoad = function() {
78
  if (this.loaded) { return; }
79
  if (!this.loadable()) { return; }
80
81
  this.onload();
82
};
83
84
Control.prototype.update = function(force) {
85
  this.updateLoad();
86
87
  Entity.prototype.update.call(this, force);
88
};
89
90
Control.prototype.onClick = function(e) {
91
  this.component('touch').onClick(e);
92
};
93
94
Control.prototype.onMove = function(e) {
95
  this.component('touch').onMove(e);
96
};
97
98
Control.prototype.onPressReset = function(e) {
99
  $.extend(true, this.config, Control.DefaultConfig);
100
101
  this.eachComponent(function(component) {
102
    for (var k in component) {
103
      var $elem = component[k];
104
      if ($elem.$change) {
105
        $elem.$change();
106
      }
107
    }
108
  });
109
110
  this.update(true);
111
  this.saveConfig();
112
};
113
114
Control.prototype.onPressChangeChatServer = function(e) {
115
  this.component('chat').onPressChangeChatServer(e);
116
};
117
118
Control.prototype.saveConfig = function() {
119
  localStorage.TPControl = JSON.stringify(this.config);
120
};
121
122
Control.prototype.loadConfig = function() {
123
  if (!localStorage.TPControl) {
124
    localStorage.TPControl = this.config;
125
  } else {
126
    try {
127
      var lastConfig = JSON.parse(localStorage.TPControl);
128
      for (var k in lastConfig) {
129
        this.config[k] = lastConfig[k];
130
      }
131
    } catch(e) {
132
      console.log(e);
133
    }
134
  }
135
};
136
137
Control.prototype.init = function() {
138
  var self = this;
139
140
  window.$ = mywindow.jQuery;
141
142
  $.extend(true, this.config, Control.DefaultConfig);
143
144
  this.loadConfig();
145
  this.saveConfig();
146
147
  dd.onChange = this.saveConfig.bind(this);
148
149
  if (this.config.screen.size[0] != Control.DefaultConfig.screen.size[0]) {
150
    $.extend(true, this.config.screen, Control.DefaultConfig.screen);
151
  }
152
153
  $('.tpc-mouse-box').remove();
154
  $('.tpc-control-settings').remove();
155
156
  var touch = new Touch();
157
  var chat = new Chat();
158
  var settings = new Settings();
159
160
  this.addComponent(touch);
161
  this.addComponent(chat);
162
  this.addComponent(settings);
163
164
  var $player = touch.$player = $(Control.PlayerSelector);
165
  var $mouseBox = touch.$mouseBox = $('<div/>').addClass('tpc-mouse-box');
166
  var $coordTooltip = touch.$coordTooltip = $('<div/>').addClass('tpc-coord-tooltip');
167
168
  var $chatSettings = settings.$chatSettings = $(Settings.ChatSelector);
169
  var $controlSettings = settings.$controlSettings = $('<div/>').addClass('tpc-control-settings');
170
171
  $player.css({ position: 'relative' });
172
  $chatSettings.css({ position: 'absolute' });
173
174
  $mouseBox.css({
175
    cursor: 'pointer',
176
    border: '2px solid rgba(150, 150, 150, 0.2)',
177
    borderRadius: '5px'
178
  });
179
180
  GM_addStyle(
181
    '.tpc-mouse-box .tpc-coord-tooltip { display: none; color: #444; font-weight: normal } ' +
182
    '.tpc-mouse-box:hover .tpc-coord-tooltip { display: block }');
183
184
  $coordTooltip.css({
185
    padding: '0px 5px',
186
    background: 'rgba(255, 255, 255, 0.8)',
187
    borderRadius: '2px'
188
  });
189
190
  $mouseBox.empty();
191
  $mouseBox.append($coordTooltip);
192
193
  $controlSettings.empty();
194
  $controlSettings.append(
195
    '<div class="chat-menu tpc-touch-menu">' +
196
      '<div class="chat-menu-header">Touch Control Settings</div>' +
197
      '<div class="chat-menu-content tpc-control-sliders"></div>' +
198
      '<div class="chat-menu-content tpc-control-checkboxes"></div>' +
199
      '<div class="chat-menu-content tpc-control-last"></div>' +
200
    '</div>' +
201
    '<div class="chat-menu tpc-chat-menu">' +
202
      '<div class="chat-menu-header">Chat Server</div>' +
203
      '<div class="chat-menu-content tpc-control-chat"></div>' +
204
    '</div>');
205
206
  $controlSettings.find('.tpc-control-sliders')
207
    .append(touch.xSlider = dd.ui.slider(
208
      'tpc-x-slider tpc-slider', 'Touch-box x-position', { min: 0, max: 1, step: 0.0005 },
209
      this.config, 'screen.position.0', function() { touch.updateMouseBox(true); }))
210
    .append(touch.ySlider = dd.ui.slider(
211
      'tpc-y-slider tpc-slider', 'Touch-box y-position', { min: 0, max: 1, step: 0.0005 },
212
      this.config, 'screen.position.1', function() { touch.updateMouseBox(true); }))
213
    .append(touch.scaleSlider = dd.ui.slider(
214
      'tpc-scale-slider tpc-slider', 'Touch-box scale', { min: 0, max: 1, step: 0.0005 },
215
      this.config, 'screen.scale', function() { touch.updateMouseBox(true); }));
216
217
  $controlSettings.find('.tpc-control-checkboxes')
218
    .append(touch.enabledCheckbox = dd.ui.checkbox(
219
      'tpc-enabled-checkbox', 'Enable touch control', this.config, 'enabled',
220
      function() {
221
        touch.$mouseBox.css({ display: self.config.enabled ? 'block' : 'none' });
222
      }))
223
    .append(touch.borderCheckbox = dd.ui.checkbox(
224
      'tpc-border-checkbox', 'Show border box', this.config, 'showBorder',
225
      function() {
226
        touch.$mouseBox.css({ border: self.config.showBorder ? '2px solid rgba(255, 255, 255, 0.5)' : 'none' });
227
      }))
228
    .append(touch.coordTooltipCheckbox = dd.ui.checkbox(
229
      'tpc-tooltip-checkbox', 'Show coord tooltip', this.config, 'showCoordTooltip',
230
      function() {
231
        if (self.config.showCoordTooltip) {
232
          touch.$mouseBox.append(touch.$coordTooltip);
233
        } else {
234
          touch.$coordTooltip.remove();
235
        }
236
      }))
237
    .append(touch.crossCheckbox = dd.ui.checkbox(
238
      'tpc-cross-checkbox', 'Use cross pointer', this.config, 'showCross',
239
      function() {
240
        touch.$mouseBox.css({ cursor: self.config.showCross ? 'crosshair' : 'default' });
241
      }))
242
    .append(touch.autoSendCheckbox = dd.ui.checkbox(
243
      'tpc-auto-send-checkbox', 'Auto-send touches', this.config, 'autoSend'))
244
    .append(touch.dropletsCheckbox = dd.ui.checkbox(
245
      'tpc-droplet-checkbox', 'Show touch droplets', this.config, 'showDroplets'));
246
247
  $controlSettings.find('.tpc-control-last')
248
    .append(touch.resetButton = dd.ui.button(
249
      'tpc-reset-button', 'Reset controller settings', this.onPressReset.bind(this)));
250
251
  $controlSettings.find('.tpc-control-chat')
252
    .append('<p><label>Current <span class="tpc-chat-server"></span></label></p>')
253
    .append(chat.chatServerButton = dd.ui.button(
254
      'tpc-chat-server-button', 'Change chat server', this.onPressChangeChatServer.bind(this)));
255
256
  $player.append($mouseBox);
257
  $chatSettings.append($controlSettings);
258
259
  $mouseBox.on('click', this.onClick.bind(this));
260
  $mouseBox.on('mousemove', this.onMove.bind(this));
261
262
  settings.update(true);
263
264
  this.loaded = true;
265
266
  this.start();
267
268
  setTimeout(function() {
269
    $('.chat-room .loading-mask').remove();
270
  }, 5000);
271
};
272
273
Control.prototype.loadable = function() {
274
  var $ = mywindow.jQuery;
275
  if (typeof $ !== 'function') { return false; }
276
277
  var hasPlayer = $(Control.PlayerSelector).length;
278
  var hasChatSettings = $(Settings.ChatSelector).length;
279
  return hasPlayer || hasChatSettings;
280
};
281
282
Control.prototype.onload = function() {
283
  this.init();
284
  if (typeof GM_info === 'object') {
285
    console.log(GM_info.script.name + ' v' + GM_info.script.version + ' loaded!');
286
  } else {
287
    console.log('Twitch Plays Control loaded!');
288
  }
289
};
290
291
var control = new Control();
292
293
setInterval(control.update.bind(control), Control.DefaultConfig.delay);
294
295
control.update();
296
297
mywindow.TPControl = control;
298
299
},{"chat":2,"dd":5,"dd-ui":4,"entity":6,"gm-shims":7,"settings":8,"touch":9,"util2":10,"window":11}],2:[function(require,module,exports){
300
var util2 = require('util2');
301
var Component = require('component');
302
303
var mywindow = require('window');
304
305
var Chat = function(def) {
306
  Component.call(this, def);
307
};
308
309
util2.inherit(Chat, Component, Chat.prototype);
310
311
Chat.InputSelector = '.ember-text-area';
312
Chat.ButtonSelector = '.send-chat-button button';
313
Chat.HiddenSelector = '.chat-hidden-overlay';
314
Chat.LogSelector = '.chat-messages .tse-content';
315
Chat.ServerAddress = '199.9.252.26:6667';
316
317
Chat.prototype.name = 'chat';
318
319
Chat.prototype.start = function() {
320
};
321
322
Chat.prototype.getChatSession = function() {
323
  if (this.chatSession) {
324
    return this.chatSession;
325
  }
326
327
  var App = mywindow.App;
328
  if (App && App.Room) {
329
    return (this.chatSession = App.Room._getTmiSession().fulfillmentValue);
330
  }
331
};
332
333
Chat.prototype.getChatConnection = function() {
334
  var chatSession = this.getChatSession();
335
  var connections = chatSession._connections;
336
  var cluster = connections.prod || connections.event;
337
  if (cluster) { return cluster; }
338
  for (var k in connections) {
339
    return connections[k];
340
  }
341
};
342
343
Chat.prototype.getCurrentChatAddress = function() {
344
  var chatSession = this.getChatSession();
345
  if (!chatSession) { return; }
346
  var connection = this.getChatConnection();
347
  if (!connection) { return; }
348
  var addr = connection._addrs[connection._currentAddressIndex];
349
  if (!addr) { return; }
350
  return addr.host + ':' + addr.port;
351
};
352
353
Chat.prototype.connectServer = function(address) {
354
  var addr = address.split(':');
355
  var chatSession = this.getChatSession();
356
  var connection = this.getChatConnection();
357
  if (!connection) {
358
    window.alert('TPC: Couldn\'t obtain a chat connection to manipulate!');
359
    return;
360
  }
361
362
  connection.close();
363
  connection._addrs = [{ host: addr[0], port: addr[1] }];
364
  connection._currentAddressIndex = 0;
365
  connection._numSocketConnectAttempts = 0;
366
  connection.open();
367
368
  var msg = 'connecting to chat server ' + address + '...';
369
  $(Chat.LogSelector + ' .ember-view:last')
370
      .before('<div class="chat-line admin"><span class="message">' + msg + '</span></div>');
371
};
372
373
Chat.prototype.isChatVisible = function() {
374
  return $(Chat.InputSelector).length && !$(Chat.HiddenSelector).is(':visible');
375
};
376
377
Chat.prototype.setInput = function(input, broadcast) {
378
  $(Chat.InputSelector).val(input).focus().change().blur();
379
  if (this.config.autoSend) {
380
    $(Chat.ButtonSelector).click();
381
  }
382
  if (!this.isChatVisible() && broadcast !== false) {
383
    localStorage.TPCInput = input;
384
  }
385
};
386
387
Chat.prototype.updateInput = function() {
388
  if (!this.entity.loaded) { return; }
389
  if (!this.config.enabled) { return; }
390
391
  if (!this.isChatVisible()) { return; }
392
393
  var input = localStorage.TPCInput;
394
  delete localStorage.TPCInput;
395
  if (typeof input === 'string' && input.length > 0) {
396
    this.setInput(input, false);
397
  }
398
};
399
400
Chat.prototype.updateChatSession = function() {
401
  if (this.chatSession) { return; }
402
403
  var TMI = mywindow.TMI;
404
  if (!TMI) { return; }
405
406
  if (this.entity.loaded) {
407
    this.getChatSession();
408
  }
409
};
410
411
Chat.prototype.update = function() {
412
  this.updateChatSession();
413
  this.updateInput();
414
};
415
416
Chat.prototype.onPressChangeChatServer = function(e) {
417
  var defaultAddress = Chat.ServerAddress;
418
  var currentAddress = this.getCurrentChatAddress();
419
  var address = window.prompt(
420
      'Enter chat server address:' +
421
      (currentAddress ?
422
        '\nCurrent ' + currentAddress :
423
        '\nExample ' + defaultAddress),
424
      defaultAddress) || '';
425
  address = address.replace(/\s/, '');
426
  if (address.length === 0) {
427
    return;
428
  }
429
  if (!address.match(':')) {
430
    address += ':6667';
431
  }
432
  this.connectServer(address);
433
};
434
435
module.exports = Chat;
436
437
},{"component":3,"util2":10,"window":11}],3:[function(require,module,exports){
438
var Component = function(def) {
439
  this.state = def || {};
440
};
441
442
Component.prototype.component = function(name) {
443
  return this.entity.component(name);
444
};
445
446
Component.prototype.start = function() {};
447
448
Component.prototype.update = function() {};
449
450
module.exports = Component;
451
452
},{}],4:[function(require,module,exports){
453
var dd = require('dd');
454
455
dd.ui = dd.ui || {};
456
457
dd.ui.checkbox = function(id, label, obj, ref, onChange) {
458
  var $elem = $('<p><label for="'+id+'"><input id="'+id+'" type="checkbox"> '+label+'</label></p>');
459
  var $input = $elem.find('input');
460
  dd.bindGetSet($elem, $input.prop.bind($input, 'checked'));
461
  $input.on('change', dd.bindElement($elem, obj, ref, onChange));
462
  return $elem;
463
};
464
465
dd.ui.slider = function(klass, label, options, obj, ref, onChange) {
466
  var $elem = $('<p><label>'+label+'</label></p>');
467
  var $slider = $('<div class="'+klass+'"></div>');
468
  $slider.slider(options);
469
  $elem.prepend($slider);
470
  dd.bindGetSet($elem, $slider.slider.bind($slider, 'value'));
471
  $slider.slider({ slide: dd.bindElement($elem, obj, ref, onChange) });
472
  return $elem;
473
};
474
475
dd.ui.button = function(klass, label, onPress) {
476
  var $elem = $('<button class="'+klass+'">'+label+'</button>');
477
  $elem.on('click', onPress);
478
  return $elem;
479
};
480
481
module.exports = dd.ui;
482
483
},{"dd":5}],5:[function(require,module,exports){
484
var dd = {};
485
486
dd.last = function(a) {
487
  return a[a.length - 1];
488
};
489
490
dd.toKey = function(obj, key) {
491
  return obj instanceof Array ? parseInt(key) : key;
492
};
493
494
dd.getByKeys = function(obj, keys, offset) {
495
  for (var i = 0, ii = keys.length - (offset || 0); i < ii; ++i) {
496
    obj = obj[dd.toKey(obj, keys[i])];
497
  }
498
  return obj;
499
};
500
501
dd.setByKey = function(obj, key, value) {
502
  obj[dd.toKey(obj, key)] = value;
503
};
504
505
dd.set = function(obj, ref, value) {
506
  var keys = ref.split('.');
507
  dd.setByKey(dd.getByKeys(obj, keys, 1), dd.last(keys), value);
508
};
509
510
dd.get = function(obj, ref) {
511
  return dd.getByKeys(obj, ref.split('.'));
512
};
513
514
dd.bindGetSet = function($elem, get, set) {
515
  $elem.$get = get;
516
  $elem.$set = set || get;
517
};
518
519
dd.bindElement = function($elem, obj, ref, onChange) {
520
  $elem.$obj = obj;
521
  $elem.$ref = ref;
522
  $elem.$change = function(e) {
523
    if (e) {
524
      dd.set(obj, ref, $elem.$get());
525
    } else {
526
      $elem.$set(dd.get(obj, ref));
527
    }
528
    if (onChange) { onChange(e); }
529
    if (dd.onChange) { dd.onChange(e); }
530
  };
531
  $elem.$change();
532
  return $elem.$change;
533
};
534
535
module.exports = dd;
536
537
},{}],6:[function(require,module,exports){
538
var Entity = function(def) {
539
  this.state = def || {};
540
  this._components = [];
541
  this._componentsByName = {};
542
};
543
544
Entity.prototype.component = function(name) {
545
  return this._componentsByName[name];
546
};
547
548
Entity.prototype.eachComponent = function(callback) {
549
  this._components.forEach(callback.bind(this));
550
};
551
552
Entity.prototype.addComponent = function(component) {
553
  if (component.entity) {
554
    component.entity.removeComponent(component);
555
  }
556
  this._componentsByName[component.name] = component;
557
  this._components.push(component);
558
  component.entity = this;
559
  component.config = this.config;
560
};
561
562
Entity.prototype.removeComponent = function(component) {
563
  var index = this._components.indexOf(component);
564
  if (index === -1) { return; }
565
  this._components.splice(index, 1);
566
  delete this._componentsByName[component.name];
567
  delete component.entity;
568
  delete component.config;
569
};
570
571
Entity.prototype.start = function() {
572
  for (var i = 0, ii = this._components.length; i < ii; ++i) {
573
    this._components[i].start();
574
  }
575
};
576
577
Entity.prototype.update = function(force) {
578
  for (var i = 0, ii = this._components.length; i < ii; ++i) {
579
    this._components[i].update(force);
580
  }
581
};
582
583
module.exports = Entity;
584
585
},{}],7:[function(require,module,exports){
586
(function (global){
587
588
if (typeof GM_addStyle === 'undefined') {
589
  global.GM_addStyle = function(style) {
590
    $('head:first').append($('<style>').text(style));
591
  };
592
}
593
594
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
595
},{}],8:[function(require,module,exports){
596
var util2 = require('util2');
597
var Component = require('component');
598
599
var Settings = function(def) {
600
  Component.call(this, def);
601
};
602
603
util2.inherit(Settings, Component, Settings.prototype);
604
605
Settings.ChatSelector = '.js-chat-settings';
606
Settings.ButtonSelector = '.settings.button';
607
608
Settings.prototype.name = 'settings';
609
610
Settings.prototype.start = function() {
611
};
612
613
Settings.prototype.updateServerLabel = function() {
614
  var $chatServer = this.$chatSettings.find('.tpc-chat-server');
615
616
  var labelAddress = $chatServer.text();
617
  var currentAddress = this.component('chat').getCurrentChatAddress();
618
  if (currentAddress !== labelAddress) {
619
    $chatServer.text(currentAddress);
620
  }
621
};
622
623
Settings.prototype.updatePosition = function(force) {
624
  var overflow = this.$chatSettings.css('overflowY') || '';
625
626
  if (overflow.match(/(auto|scroll)/)) {
627
    this.$controlSettings.css({ position: 'static', left: 'none', top: 'none' });
628
    return;
629
  }
630
631
  var minWidth = Math.max(200, this.$chatSettings.width());
632
  var position = { left: 0, top: 0 };
633
  var offset = this.$chatSettings.offset();
634
  var isSlim = offset.left > 0 && offset.left < minWidth;
635
636
  this.$controlSettings.css({
637
    position: 'absolute',
638
    minWidth: minWidth,
639
    left: position.left + (minWidth + 5) * (isSlim ? 1 : -1),
640
    top: position.top + this.$chatSettings.height() - this.$controlSettings.height()
641
  });
642
};
643
644
Settings.prototype.update = function(force) {
645
  if (!this.entity.loaded) { return; }
646
647
  if (!this.$chatSettings.length) { return; }
648
  if (!this.$chatSettings.is(':visible') && force !== true) { return; }
649
650
  this.updateServerLabel();
651
  this.updatePosition();
652
};
653
654
module.exports = Settings;
655
656
},{"component":3,"util2":10}],9:[function(require,module,exports){
657
var util2 = require('util2');
658
var Component = require('component');
659
660
var Touch = function(def) {
661
  Component.call(this, def);
662
};
663
664
util2.inherit(Touch, Component, Touch.prototype);
665
666
Touch.SizeEdge = [false, false];
667
668
Touch.prototype.name = 'touch';
669
670
Touch.prototype.start = function() {
671
};
672
673
Touch.prototype.getBorderSize = function() {
674
  return parseInt(this.$mouseBox.css('borderTopWidth'));
675
};
676
677
Touch.prototype.getTouchPosition = function(e) {
678
  var offset = this.$mouseBox.offset();
679
  var borderSize = this.getBorderSize();
680
  var x = e.clientX - offset.left - 2 * borderSize;
681
  var y = e.clientY - offset.top - 2 * borderSize;
682
683
  var minX = 0 + (Touch.SizeEdge[0] ? 0 : 1);
684
  var minY = 0 + (Touch.SizeEdge[1] ? 0 : 1);
685
  var maxX = this.config.screen.size[0] - (Touch.SizeEdge[0] ? 0 : 1);
686
  var maxY = this.config.screen.size[1] - (Touch.SizeEdge[1] ? 0 : 1);
687
688
  var touchX = Math.ceil(x / this.scale);
689
  var touchY = Math.ceil(y / this.scale);
690
  var valid = (touchX >= minX && touchX <= maxX) &&
691
              (touchY >= minY && touchY <= maxY);
692
  return {
693
    mouse: [x, y],
694
    position: [touchX, touchY],
695
    input: touchX + ',' + touchY,
696
    valid: valid
697
  };
698
};
699
700
Touch.prototype.spawnDroplet = function(position) {
701
  var $drop = $('<div/>').addClass('tpc-droplet');
702
  var size = 10;
703
  $drop.css({
704
    background: 'rgba(255, 255, 255, 0.8)',
705
    borderRadius: size,
706
    position: 'absolute',
707
    left: position[0] - size / 2,
708
    top: position[1] - size / 2,
709
    width: size,
710
    height: size
711
  });
712
  this.$mouseBox.append($drop);
713
  $drop
714
    .animate({
715
      left: position[0],
716
      top: position[1],
717
      width: 0,
718
      height: 0
719
    }, this.config.streamDelay * 1000)
720
    .queue(function() {
721
      $drop.remove();
722
      $drop.dequeue();
723
    });
724
};
725
726
Touch.prototype.updateMouseBox = function(force) {
727
  var playerWidth = this.$player.width();
728
  var playerHeight = this.$player.height() - this.config.screen.barHeight;
729
730
  if ((this.playerWidth === playerWidth &&
731
       this.playerHeight === playerHeight) && force !== true) {
732
    return;
733
  }
734
735
  this.playerWidth = playerWidth;
736
  this.playerHeight = playerHeight;
737
738
  var aspect = playerWidth / playerHeight;
739
740
  var excessWidth = 0;
741
  if (aspect > this.config.screen.aspect) {
742
    excessWidth = playerWidth - playerHeight * this.config.screen.aspect;
743
  }
744
745
  this.scale = this.config.screen.scale * playerHeight / this.config.screen.size[1];
746
747
  var borderSize = this.getBorderSize();
748
  var width = this.scale * this.config.screen.size[0];
749
  var height = this.scale * this.config.screen.size[1];
750
751
  this.$mouseBox.css({
752
    position: 'absolute',
753
    left: excessWidth / 2 + (playerWidth - width - excessWidth) * this.config.screen.position[0] - borderSize,
754
    top: (playerHeight - height) * this.config.screen.position[1] - borderSize,
755
    width: width,
756
    height: height
757
  });
758
759
  if (!this.component('settings').$chatSettings.is(':visible')) {
760
    this.$mouseBox.stop(true, true).css({ background: 'transparent' });
761
    return;
762
  }
763
764
  this.$mouseBox
765
    .stop(true, true)
766
    .animate({ backgroundColor: 'rgba(255, 255, 255, 0.5)' }, 100)
767
    .delay(1000)
768
    .animate({ backgroundColor: 'rgba(255, 255, 255, 0)' })
769
    .animate({ background: 'transparent' }, 0);
770
};
771
772
Touch.prototype.update = function(force) {
773
  if (!this.entity.loaded) { return; }
774
  if (!this.config.enabled) { return; }
775
776
  this.updateMouseBox(force);
777
};
778
779
Touch.prototype.onClick = function(e) {
780
  var touch = this.getTouchPosition(e);
781
  if (!touch.valid) { return; }
782
  this.component('chat').setInput(touch.input);
783
  if (this.config.showDroplets) {
784
    this.spawnDroplet(touch.mouse);
785
  }
786
};
787
788
Touch.prototype.onMove = function(e) {
789
  if (!this.config.showCoordTooltip) { return; }
790
  var touch = this.getTouchPosition(e);
791
  var borderSize = this.getBorderSize();
792
  this.$coordTooltip
793
    .text(touch.valid ? touch.input : '')
794
    .css({
795
      position: 'absolute',
796
      left: touch.mouse[0] + borderSize + 15,
797
      top: touch.mouse[1] + borderSize - this.$coordTooltip.outerHeight() / 2
798
    });
799
};
800
801
module.exports = Touch;
802
803
},{"component":3,"util2":10}],10:[function(require,module,exports){
804
/*
805
 * util2.js by Meiguro - MIT License
806
 */
807
808
var util2 = (function(){
809
810
var util2 = {};
811
812
util2.noop = function() {};
813
814
util2.copy = function(a, b) {
815
  b = b || (a instanceof Array ? [] : {});
816
  for (var k in a) { b[k] = a[k]; }
817
  return b;
818
};
819
820
util2.inherit = function(child, parent, proto) {
821
  child.prototype = Object.create(parent.prototype);
822
  child.prototype.constructor = child;
823
  if (proto) {
824
    util2.copy(proto, child.prototype);
825
  }
826
  return child.prototype;
827
};
828
829
if (typeof module !== 'undefined') {
830
  module.exports = util2;
831
}
832
833
return util2;
834
835
})();
836
837
},{}],11:[function(require,module,exports){
838
/* global unsafeWindow */
839
module.exports = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
840
841
},{}]},{},[1])