AWBW Move Planner Button in Game List

Adds a Move Planner button to each match. If it's a waiting game, the moveplanner loads the map. Completed games don't get a button.

  1. // ==UserScript==
  2. // @name AWBW Move Planner Button in Game List
  3. // @namespace https://awbw.amarriner.com/
  4. // @version 0.1
  5. // @description Adds a Move Planner button to each match. If it's a waiting game, the moveplanner loads the map. Completed games don't get a button.
  6. // @author Vincent
  7. // @license MIT
  8. // @match https://awbw.amarriner.com/yourgames.php
  9. // @match https://awbw.amarriner.com/yourturn.php
  10. // @match https://awbw.amarriner.com/following.php*
  11. // @match https://awbw.amarriner.com/profile.php*
  12. // @match https://awbw.amarriner.com/gamescurrent_all.php*
  13. // @match https://awbw.amarriner.com/gameswait.php
  14. // @icon https://awbw.amarriner.com/terrain/moveplanner.gif
  15. // @grant none
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. function createMovePlannerButton(plannerUrl, tooltipText) {
  22. const gameInfoTd = this;
  23. if (gameInfoTd.querySelector('.move-planner-btn')) return; // Prevent duplicates
  24.  
  25. gameInfoTd.style.position = 'relative';
  26.  
  27. const btn = document.createElement('a');
  28. btn.href = plannerUrl;
  29. btn.target = '_blank';
  30. btn.title = tooltipText;
  31. btn.className = 'move-planner-btn';
  32. btn.style.position = 'absolute';
  33. btn.style.bottom = '6px';
  34. btn.style.right = '6px';
  35. btn.style.zIndex = '10';
  36. btn.style.display = 'inline-block';
  37. btn.style.padding = '2px';
  38. btn.style.border = '1px solid #888';
  39. btn.style.backgroundColor = '#EEE';
  40.  
  41. const icon = document.createElement('img');
  42. icon.src = 'https://awbw.amarriner.com/terrain/moveplanner.gif';
  43. icon.alt = 'Move Planner';
  44. icon.style.width = '24px';
  45. icon.style.height = '24px';
  46. icon.style.cursor = 'pointer';
  47. icon.style.imageRendering = 'pixelated';
  48.  
  49. btn.appendChild(icon);
  50. gameInfoTd.appendChild(btn);
  51. }
  52.  
  53. function getGameStateFromColor(td) {
  54. const bg = getComputedStyle(td).backgroundColor;
  55. if (bg === 'rgb(193, 255, 208)') return 'waiting';
  56. if (bg === 'rgb(209, 250, 255)') return 'current';
  57. return 'completed';
  58. }
  59.  
  60. document.querySelectorAll('tr').forEach(row => {
  61. const tds = row.querySelectorAll('td.small');
  62. if (tds.length < 3) return;
  63.  
  64. const gameInfoTd = tds[0];
  65. const mapInfoTd = tds[1];
  66. const playerInfoTd = tds[2];
  67.  
  68. const gameLinks = gameInfoTd.querySelectorAll('a[href*="game.php?games_id="]');
  69.  
  70. // Use game title cell to detect game state
  71. const titleTd = row.querySelector('td.limits');
  72. if (!titleTd) return;
  73.  
  74. const gameState = getGameStateFromColor(titleTd);
  75. if (gameState === 'completed') return;
  76.  
  77. let plannerUrl = null;
  78. let tooltipText = 'Move Planner';
  79.  
  80. if (gameState === 'waiting') {
  81. const mapIdMatch = mapInfoTd.innerHTML.match(/maps_id=(\d+)/);
  82. if (mapIdMatch) {
  83. plannerUrl = `https://awbw.amarriner.com/moveplanner.php?maps_id=${mapIdMatch[1]}`;
  84. tooltipText = 'Move Planner (Map)';
  85. }
  86. } else if (gameState === 'current') {
  87. const gameIdMatch = gameLinks[0].href.match(/games_id=(\d+)/);
  88. if (gameIdMatch) {
  89. plannerUrl = `https://awbw.amarriner.com/moveplanner.php?games_id=${gameIdMatch[1]}`;
  90. }
  91. }
  92.  
  93. if (!plannerUrl) return;
  94.  
  95. createMovePlannerButton.call(gameInfoTd, plannerUrl, tooltipText);
  96. });
  97. })();