// ==UserScript==
// @name DuelingNexus Chat Improvements Plugin
// @namespace https://duelingnexus.com/
// @version 0.6.2
// @description Revamps the chat and visual features of dueling.
// @author Sock#3222
// @grant none
// @match https://duelingnexus.com/game/*
// ==/UserScript==
// TODO: add github link
let makeReadOnly = function (obj, prop) {
let val = obj[prop];
delete obj[prop];
Object.defineProperty(obj, prop, {
value: val,
writable: false,
enumerable: true,
configurable: true,
});
return val;
}
let ChatImprovements = {
log: [],
storage: {
_cache: null,
get: null,
set: null,
},
};
const LOCAL_STORAGE_KEY = "ChatImprovementsCache";
let updateLocalStorage = function () {
let json = JSON.stringify(ChatImprovements.storage._cache);
localStorage.setItem("ChatImprovementsCache", json);
};
let checkCache = function () {
if(ChatImprovements.storage._cache) {
return;
}
let localCopy;
try {
localCopy = localStorage.getItem(LOCAL_STORAGE_KEY);
localCopy = JSON.parse(localCopy)
}
catch(e) {
console.error("Error parsing local copy:", localCopy);
}
ChatImprovements.storage._cache = localCopy || {};
updateLocalStorage();
};
ChatImprovements.storage.set = function (item, value) {
checkCache();
ChatImprovements.storage._cache[item] = value;
updateLocalStorage();
return value;
};
ChatImprovements.storage.get = function (item) {
checkCache();
return ChatImprovements.storage._cache[item];
};
ChatImprovements.storage.clear = function (item) {
checkCache();
ChatImprovements.storage._cache = {};
updateLocalStorage();
};
// standard getter/setter properties
let defaultProperties = {
playSounds: true,
temporaryChat: true,
showOptions: false,
showNormalEvents: true,
showChainEvents: true,
};
for(let [prop, defaultValue] of Object.entries(defaultProperties)) {
// define if unset (inital run)
if(typeof ChatImprovements.storage.get(prop) === "undefined") {
ChatImprovements.storage.set(prop, defaultValue);
}
// getter & setter
Object.defineProperty(ChatImprovements, prop, {
get: function () {
return ChatImprovements.storage.get(prop);
},
set: function (value) {
return ChatImprovements.storage.set(prop, value);
},
});
}
makeReadOnly(ChatImprovements, "log");
window.ChatImprovements = ChatImprovements;
let waitFrame = function () {
return new Promise(resolve => {
requestAnimationFrame(resolve); //faster than set time out
});
};
const waitForElementJQuery = async function (selector, source = $("body")) {
let query;
while (source.find(selector).length === 0) {
await waitFrame();
}
return query;
};
let onload = function () {
// css
$("head").append($(`<style>
#ci-ext-misc {
float: left;
width: 25%;
overflow-x: hidden;
overflow-y: auto;
box-sizing: border-box;
}
#card-column {
float: none;
width: auto;
}
#ci-ext-misc-sections > div {
overflow-x: hidden;
overflow-y: auto;
box-sizing: border-box;
}
#ci-ext-misc-sections > div:hover {
z-index: 10;
}
#ci-ext-log > p, #ci-ext-event-log > p {
padding: 0;
margin: 3px;
}
#ci-ext-event-log .interact-name {
cursor: pointer;
}
#ci-ext-log, #ci-ext-event-log, #ci-ext-options {
background: rgb(0, 0, 0);
background: rgba(0, 0, 0, 0.7);
}
@keyframes fullScale {
from {
transform: scale(1);
}
to {
transform: scale(2);
}
}
.material-preview {
margin: 3px;
}
#ci-ext-misc-buttons {
display: flex;
justify-content: space-between;
}
#ci-ext-misc-buttons > button {
flex-grow: 1;
flex-basis: 0;
}
</style>`));
// TODO: move chaining options on bottom right
// TODO: add hide options for sleeves/avatars
// boilerplate
const globalOptions = f;
const playSound = Q;
const sendEvent = K;
const gameChatContent = $("#game-chat-content");
const gameChatTextbox = $("#game-chat-textbox");
const gameChatArea = $("#game-chat-area");
const showCardInColumn = Cc;
const SECONDS = 1000;
const monsterTypeMap = {};
for(let key in Wf) {
let value = Wf[key];
monsterTypeMap[value] = parseInt(key, 10);
}
window.monsterTypeMap = monsterTypeMap;
const isTrapCard = (card) => card.type & monsterTypeMap["Trap"];
const isSpellCard = (card) => card.type & monsterTypeMap["Spell"];
const isMonster = (card) => !isTrapCard(card) && !isSpellCard(card);
const isToken = (card) => card.type & monsterTypeMap["Token"];
const isXyzMonster = (card) => card.type & monsterTypeMap["Xyz"];
const isPendulumMonster = (card) => card.type & monsterTypeMap["Pendulum"];
const isLinkMonster = (card) => card.type & monsterTypeMap["Link"];
const isFusionMonster = (card) => card.type & monsterTypeMap["Fusion"];
const isRitualMonster = (card) => isMonster(card) && (card.type & monsterTypeMap["Ritual"]);
const isSynchroMonster = (card) => card.type & monsterTypeMap["Synchro"];
const isNormalMonster = (card) => card.type & monsterTypeMap["Normal"];
gameChatContent.css("overflow-y", "auto")
// .css("height", "230px")
// .css("background-color", "transparent");
// gameChatArea.css("background-color", "rgba(0, 0, 0)")
// .css("background-color", "rgba(0, 0, 0, 0.7)");
let chatLog = $("<div id=ci-ext-log>");
let chatEventLog = $("<div id=ci-ext-event-log>");
/**/
Gb.GameSet = window.Td = function Td(a) {
Q("set");
// console.log("Td", a);
};
Gb.GameSummoning = window.Ud = function Ud(a) {
xc(a.cardCode, function() {
Q("summon");
// console.log("Ud", a);
kf(a.cardCode);
});
return true;
}
Gb.GameSpSummoning = window.Vd = function Vd(a) {
xc(a.cardCode, function() {
Q("summon-special");
// console.log("Vd", a);
kf(a.cardCode);
});
return true;
}
Gb.GameFlipSummoning = window.Wd = function Wd(a) {
xc(a.cardCode, function() {
Q("summon-flip");
// console.log("Wd", a);
kf(a.cardCode);
});
return true;
}
const CHAIN_SYMBOL = "\uD83D\uDD17";
Gb.GameChaining = window.Xd = function Xd(a) {
xc(a.cardCode, function() {
Q("activate");
let cardName = a.cardCode ? "#@" + a.cardCode : "A card";
// console.log("!!!!", cardName);
// notifyEvent(" of " + cardName + " was activated (from " + GameLocations[a.location]);
let message = `Chain Link ${a.chainCount}: ${cardName}`
if(a.chainCount > 1) {
message = CHAIN_SYMBOL + " " + message;
}
notifyEvent(message, Events.CHAIN);
kf(a.cardCode);
});
return true;
}
/*
GameDamage: Yd,
GameRecover: Zd,
GamePayLpCost: $d,
GameLpUpdate: ae,
GameAttack: be,
GameBattle: ce,
GameReloadField: de,
GameTagSwap: ee,
GameFieldDisabled: fe,
GameWaiting: ge,
GameEquip: he,
GameBecomeTarget: ie,
GameWin: je,
GameTossCoin: ke,
GameTossDice: le,
GameAddCounter: me,
GameRemoveCounter: ne,
GameConfirmCards: oe,
GameConfirmDeckTop: pe,
GameDeckTop: qe,
GameRetry: re,
GameSelectIdleCommand: se,
GameSelectBattleCommand: te,
GameSelectCard: ue,
GameSelectUnselect: ve,
GameSortCards: we,
GameSelectTribute: xe,
GameSelectYesNo: ye,
GameSelectEffectYesNo: ze,
GameSelectChain: Ae,
GameSelectPosition: Be,
GameSelectOption: Ce,
GameSelectSum: De,
GameSelectPlace: Ee,
GameSelectCounter: Fe,
GameAnnounceAttrib: Ge,
GameAnnounceRace: He,
GameAnnounceNumber: Ie,
GameAnnounceCard: Je
*/
let eventTypeList = [
];
let timestamp = function () {
let now = new Date();
return [
now.getHours(),
now.getMinutes(),
now.getSeconds()
].map(time => time.toString().padStart(2, "0")).join(":");
}
const scrollToBottom = function (el) {
el = $(el);
el.animate({
scrollTop: el.prop("scrollHeight")
}, 150);
}
const MESSAGE_PARSE_REGEX = /#@(\d+)|.+?/g;
let colorOfCard = function (card) {
if(isTrapCard(card)) {
return "#BC5A84";
}
else if(isSpellCard(card)) {
return "#1D9E74";
}
else {
return "#B83D00";
}
}
let displayMessage = function (content, color, ...kinds) {
//showCardInColumn
let matches;
let message = $("<p>");
while(matches = MESSAGE_PARSE_REGEX.exec(content)) {
let id = parseInt(matches[1]);
let card = X[id];
if(id && card) {
let interactive = $("<span>")
.css("color", "white")
.css("background-color", colorOfCard(card))
.data("id", id)
.addClass("interact-name");
interactive.hover(function () {
showCardInColumn(id);
});
interactive.text('"' + card.name + '"');
message.append(interactive);
}
else {
message.append(matches[0]);
}
}
for(let kind of kinds) {
message.addClass(kind);
}
if(color) {
message.css("color", color);
}
gameChatContent.append(message);
let copy = message.clone(true);
if(kinds.indexOf("notified-event") !== -1) {
$(".interact-name", copy).unbind().click(function () {
showCardInColumn($(this).data("id"));
showCardColumn.click();
});
chatEventLog.append(copy);
}
else {
chatLog.append(copy);
}
// scroll to message
scrollToBottom(chatLog);
scrollToBottom(gameChatContent);
// handle UI
if(ChatImprovements.temporaryChat) {
if(gameChatContent.children().length > 10) {
gameChatArea.find("p:first").remove();
}
setTimeout(function() {
message.remove();
}, 10 * SECONDS);
}
return message;
}
ChatImprovements.displayMessage = displayMessage;
// overwrite send message
window.td = displayMessage;
let unifyMessage = function (message) {
return timestamp() + " " + message;
}
let displayOpponentsMessage = function (a) {
if(ChatImprovements.playSounds) {
playSound("chat-message");
}
let playerId = a.playerId;
let message = a.message;
let color;
if(0 <= playerId && 3 >= playerId) {
let name = B[playerId].name;
message = "[" + name + "]: " + message;
}
else {
color = "yellow";
}
message = unifyMessage(message);
displayMessage(message, color);
}
gameChatTextbox.unbind();
gameChatTextbox.keyup(function(ev) {
if(ev.keyCode == 13) {
let message = gameChatTextbox.val();
gameChatTextbox.val("");
sendEvent({
type: "SendChatMessage",
message: message
});
message = unifyMessage("[" + Ib + "]: " + message);
// TODO: assign each person a different color?
if(4 > A) {
displayMessage(message);
}
else {
displayMessage(message, "yellow");
}
}
});
// create sections
let miscContainer = $("<div id=ci-ext-misc>");
let miscSections = $("<div id=ci-ext-misc-sections>");
let optionsColumn = $("<div id=ci-ext-options>");
let cardColumn = $("#card-column");
let gameContainer = $("#game-container");
gameContainer.prepend(miscContainer);
class GameOption {
constructor(tag, id, option, type, info = {}) {
this.tag = tag;
this.id = id;
this.option = option;
this.type = type;
this.isBaseOption = !!info.isBaseOption;
this.showValue = !!info.showValue;
this.decoration = info.decoration || (() => "");
this.resolveOnLoad = info.resolveOnLoad;
this.resolve = info.resolve;
if(this.resolve) {
this.resolve = this.resolve.bind(this);
}
if(this.isRange) {
this.min = info.min;
this.max = info.max;
}
}
get isRange() {
return this.type === "range";
}
get isCheckbox() {
return this.type === "checkbox";
}
toElement(formatTable = true) {
let base = $("<input>");
base.attr("id", id)
.attr("type", this.type);
if(this.isRange) {
base.attr("min", this.min)
.attr("max", this.max);
}
let currentValue;
if(this.isBaseOption) {
currentValue = globalOptions.options[this.option];
}
else {
currentValue = ChatImprovements[this.option];
}
if(this.isCheckbox) {
base.prop("checked", currentValue);
}
else {
base.val(currentValue);
}
base.data("option", this.option);
let onValueChange = () => {
let option = this.option;
let value = this.isCheckbox ? base.prop("checked") : base.val();
if(this.isBaseOption) {
globalOptions.options[option] = value;
globalOptions.save();
// NOTE: can break
jd && jd(option, value);
}
else {
ChatImprovements[option] = value;
}
if(updateValueTd) {
updateValueTd.text(this.decoration(value));
}
if(this.resolve) {
this.resolve(value);
}
};
let updateValueTd;
if(this.showValue) {
updateValueTd = $("<td>");
// DRY broken here a bit
updateValueTd.text(this.decoration(currentValue))
.css("cursor", "pointer");
updateValueTd.click(() => {
let newValue = prompt("Enter the new value for \"" + this.tag + "\":");
if(newValue !== null) {
base.val(newValue);
onValueChange();
}
});
}
base.change(onValueChange);
if(!formatTable) {
return base;
}
let tr = $("<tr>");
tr.append($("<td>").text(this.tag));
tr.append($("<td>").append(base));
if(this.showValue) {
tr.append(updateValueTd);
}
return tr;
}
}
/*
var a = $(this).data("option"),
b = $(this).val();
$("#options-" + a + "-value").text(b + "%");
f.options[a] = b;
f.save();
jd && jd(a, b)
*/
// initialize options column
let optionsColumnInfo = [
[
"Game Options",
new GameOption(
"Sounds volume",
"ci-ext-option-sounds-volume",
"sounds",
"range",
{
min: 0,
max: 100,
isBaseOption: true,
showValue: true,
decoration: (x) => `${x}%`,
}
),
new GameOption(
"Music volume",
"ci-ext-option-music-volume",
"music",
"range",
{
min: 0,
max: 100,
isBaseOption: true,
showValue: true,
decoration: (x) => `${x}%`,
}
),
new GameOption(
"Animations speed",
"ci-ext-option-animation-speed",
"speed",
"range",
{
min: 0,
max: 500,
isBaseOption: true,
showValue: true,
decoration: (x) => `${x}%`,
}
),
],
[
new GameOption(
"Place monsters automatically",
"ci-ext-option-auto-place-monsters",
"auto-place-monsters",
"checkbox",
{
isBaseOption: true,
}
),
new GameOption(
"Place spells automatically",
"ci-ext-option-auto-place-spells",
"auto-place-spells",
"checkbox",
{
isBaseOption: true,
}
),
new GameOption(
"Temporary chat",
"ci-ext-option-temporary-chat",
"temporaryChat",
"checkbox",
{
resolve: function () {
// TODO: hide existing chat
}
}
),
new GameOption(
"Play chat sounds",
"ci-ext-option-chat-sounds",
"playSounds",
"checkbox",
),
new GameOption(
"Show options",
"ci-ext-option-show-options",
"showOptions",
"checkbox",
{
resolve: function (value) {
console.log("Resolving showOptions value", value);
$("#options-show-button").toggle(value);
return this;
},
resolveOnLoad: true,
}
),
],
[
"Event Filters",
new GameOption(
"Show normal events",
"ci-ext-option-hide-all-events",
"showNormalEvents",
"checkbox",
),
new GameOption(
"Show chaining events",
"ci-ext-option-hide-all-events",
"showChainEvents",
"checkbox",
),
]
];
for(let stratum of optionsColumnInfo) {
let table = $("<table>");
while(stratum.length && typeof stratum[0] === "string") {
let title = stratum.shift();
optionsColumn.append($("<h2>").text(title));
}
for(let option of stratum) {
let tr = option.toElement(true);
if(option.resolveOnLoad) {
console.log(tr);
option.resolve();
}
table.append(tr);
}
optionsColumn.append(table);
}
/*.click(function() {
var a = $(this).data("option"),
b = $(this).val();
$("#options-" + a + "-value").text(b + "%");
f.options[a] = b;
f.save();
if(jd) {
jd(a, b);
}
})*/
let miscSectionButtons = $("<div id=ci-ext-misc-buttons>");
// moved earlier for hideMiscBut
let minimizeToggle = $("<button class=engine-button title=minimize>−</button>")
.data("toggled", false)
.click(function () {
let toggled = $(this).data("toggled");
gameChatContent.toggle(toggled);
gameChatTextbox.toggle(toggled);
toggled = !toggled;
$(this).data("toggled", toggled);
scrollToBottom(gameChatContent);
});
const hideMiscBut = function (but) {
return function (ev) {
for(let child of miscSections.children()) {
let isVisible = child.id === but;
$(child).toggle(isVisible);
if(isVisible) {
scrollToBottom(child);
}
}
gameChatContent.toggle(but !== "ci-ext-log" && but !== "ci-ext-event-log" && !minimizeToggle.data("toggled"));
};
};
// button toggles for sections
let showCardColumn = $("<button id=ci-ext-show-card-column class=engine-button>Card Info</button>");
let showChatLog = $("<button id=ci-ext-show-chat-log class=engine-button>Chat Log</button>");
let showEventLog = $("<button id=ci-ext-show-event-log class=engine-button>Event Log</button>");
let showOptions = $("<button id=ci-ext-show-options class=engine-button>Options</button>");
showCardColumn.click(hideMiscBut("card-column"));
showChatLog.click(hideMiscBut("ci-ext-log"));
showEventLog.click(hideMiscBut("ci-ext-event-log"));
showOptions.click(hideMiscBut("ci-ext-options"));
miscSectionButtons.append(showCardColumn, showChatLog, showEventLog, showOptions);
miscContainer.append(miscSectionButtons);
cardColumn.detach();
miscSections.append(cardColumn);
miscSections.append(chatLog);
miscSections.append(chatEventLog);
miscSections.append(optionsColumn);
showCardColumn.click();
miscContainer.append(miscSections);
// update ui
// TODO: toggle even newly inserted messages
// let updateMuteToggleText;
// let muteToggle = $("<button class=engine-button></button>")
// .click(function () {
// ChatImprovements.playSounds = !ChatImprovements.playSounds;
// updateMuteToggleText();
// })
// .css("float", "right");
// updateMuteToggleText = function () {
// muteToggle.text(ChatImprovements.playSounds ? "Mute" : "Unmute");
// };
// updateMuteToggleText();
// let updateNotificationToggleText;
// let notificationToggle = $("<button class=engine-button></button>")
// .click(function () {
// ChatImprovements.showEvents = !ChatImprovements.showEvents;
// updateNotificationToggleText();
// $("#game-chat-area .notified-event").toggle(ChatImprovements.showEvents);
// })
// .css("float", "right");
// updateNotificationToggleText = function () {
// notificationToggle.text(ChatImprovements.showEvents ? "Hide events" : "Show events");
// };
// updateNotificationToggleText();
// let
gameChatArea.prepend(
minimizeToggle, /*muteToggle,*/ /*notificationToggle*/
);
// listeners[type] = [...];
let listeners = {};
ChatImprovements.addEventListener = function (ev, cb) {
// TODO: verify
listeners[ev] = listeners[ev] || [];
listeners[ev].push(cb);
}
// reference
const log = ChatImprovements.log;
rb.shift = function (...args) {
let res = Array.prototype.shift.apply(rb, args);
log.push(res);
if(typeof res.length !== "undefined") {
alert("whoa! unexpected arguments passed to sb.shift!");
}
let eventType = res.type;
if(listeners[eventType]) {
for(let cb of listeners[eventType]) {
cb(res);
}
}
return res;
}
const Events = {
CHAIN: "chain",
NORMAL: "normal",
};
const notificationColors = {
[Events.NORMAL]: "#00FF00",
[Events.CHAIN]: "#AAFFAA",
};
const notificationPrefixes = {
[Events.NORMAL]: "Event: ",
[Events.CHAIN]: "",
};
const eventEnabledKeys = {
[Events.NORMAL]: "showNormalEvents",
[Events.CHAIN]: "showChainEvents",
};
const notifyEvent = function (event, kind = Events.NORMAL) {
let prefix = notificationPrefixes[kind];
let color = notificationColors[kind];
let message = displayMessage(prefix + event, color, "notified-event", "event-" + kind);
let enabledKey = eventEnabledKeys[kind];
message.toggle(ChatImprovements[enabledKey]);
};
const GameLocations = {
TOKEN_PILE: 0,
DECK: 1,
HAND: 2,
FIELD_MONSTER: 4,
FIELD_SPELLTRAP: 8,
FIELD: 4 | 8,
GY: 16,
BANISHED: 32,
EXTRA_DECK: 64,
XYZ_MATERIAL: 128,
};
const LocationNames = {
[GameLocations.TOKEN_PILE]: "token pile",
[GameLocations.DECK]: "the Deck",
[GameLocations.HAND]: "the hand",
[GameLocations.FIELD_MONSTER]: "a Monster Zone",
[GameLocations.FIELD_SPELLTRAP]: "a Spell & Trap Zone",
[GameLocations.GY]: "the GY",
[GameLocations.BANISHED]: "being banished",
[GameLocations.EXTRA_DECK]: "the Extra Deck",
192: " an Xyz Monster [bugged response, please report!]",
};
let cardCodeToSkip = null;
let movedFromTo = function (move, start, end) {
return (move.previousLocation & start) !== 0 &&
(move.currentLocation & end) !== 0;
}
ChatImprovements.addEventListener("GameMove", function (move) {
let cardName = move.cardCode ? "#@" + move.cardCode : "A card";
if(move.cardCode) {
cardCodeToSkip = move.cardCode;
}
// sent to GY
if(movedFromTo(move, GameLocations.XYZ_MATERIAL, GameLocations.GY) ||
movedFromTo(move, GameLocations.XYZ_MATERIAL, GameLocations.BANISHED)) {
status = "was detached as Xyz Material"
}
else if(move.currentLocation === GameLocations.GY) {
status = "was sent to the GY from " + LocationNames[move.previousLocation];
}
// returned to the deck
else if(move.currentLocation === GameLocations.DECK) {
status = "was shuffled/placed into the Deck from " + LocationNames[move.previousLocation];
}
// returned to the extra deck
else if(move.currentLocation === GameLocations.EXTRA_DECK) {
status = "was returned to the Extra Deck from " + LocationNames[move.previousLocation];
}
// attached as xyz material?
else if(move.currentLocation & GameLocations.XYZ_MATERIAL) {
status = "was attached as Xyz Material from " + LocationNames[move.previousLocation];
}
// banished
else if(move.currentLocation === GameLocations.BANISHED) {
status = "was banished from " + LocationNames[move.previousLocation];
}
// sent to hand
else if(movedFromTo(move, GameLocations.GY, GameLocations.HAND)) {
// console.log("why??????");
status = "was returned from the GY to the hand";
}
else if(movedFromTo(move, GameLocations.DECK, GameLocations.HAND)) {
status = "was added from the Deck to the hand";
}
else if(movedFromTo(move, GameLocations.BANISHED, GameLocations.HAND)) {
status = "was added to the hand from being banished";
}
else if(movedFromTo(move, GameLocations.FIELD, GameLocations.HAND)) {
status = "was returned from the field to the hand";
}
else if(movedFromTo(move, GameLocations.EXTRA_DECK, GameLocations.HAND)) {
status = "was added to the hand from the face-up Extra Deck";
}
// monster summons
else if(move.currentLocation === GameLocations.FIELD_MONSTER) {
status = "was Summoned from " + LocationNames[move.previousLocation];
}
// spell card activations
else if(move.currentLocation === GameLocations.FIELD_SPELLTRAP) {
// TODO: set vs. activate
console.log(move);
status = "was activated/set from " + LocationNames[move.previousLocation];
}
else if(movedFromTo(move, GameLocations.FIELD, GameLocations.TOKEN_PILE)) {
status = "was removed from the field";
}
else {
// 0 from 4
status = "- UNSURE!! " + move.currentLocation + " from " + move.previousLocation;
}
notifyEvent(cardName + " " + status);
// TODO: more
});
ChatImprovements.addEventListener("cfReveal", function (code) {
if(code && code !== cardCodeToSkip) {
notifyEvent("Revealed #@" + code);
}
cardCodeToSkip = null;
});
ChatImprovements.addEventListener("targetCardAnimation", function (code) {
if(code) {
notifyEvent("Targeted #@" + code);
}
});
// redefine window resizing
window.Wb = function Wb() {
var a = $("#ci-ext-misc-sections").position().top;
// originally: - 24
const offset = 37;
$("#ci-ext-misc-sections div")
.css("max-height", $(window).height() - a - offset);
$("#game-siding-column")
.css("max-height", $(window).height() - a - offset);
a = 4 === Ab ? 7 : 6;
var b = $(window).width() - $("#ci-ext-misc").width() - 50,
// c = $(window).height();// - $("#game-chat-area").height() - 8 - 48;
c = $(window).height() - $("#game-chat-textbox").outerHeight() - 8 - 48;
9 * c / a < b ? ($("#game-field").css("height", c + "px"), b = c / a, $("#game-field").css("width", 9 * b + "px")) : ($("#game-field").css("width", b + "px"), b /= 9, $("#game-field").css("height", b * a + "px"));
$(".game-field-zone").css("width",
b + "px").css("height", b + "px");
$(".game-field-hand").css("width", 5 * b + "px").css("height", b + "px");
Cb = b;
Db = Math.floor(.95 * b);
E = 177 * Db / 254;
Zc(m[0]);
Zc(m[1]);
$("#game-position-atk-up").css("width", E);
$("#game-position-atk-up").css("height", Db);
$("#game-position-atk-up").css("margin-right", Db - E + 3);
$("#game-position-atk-down").css("width", E);
$("#game-position-atk-down").css("height", Db);
$("#game-position-atk-down").css("margin-right", Db - E + 3);
$("#game-position-def-up").css("width", E);
$("#game-position-def-up").css("height",
Db);
$("#game-position-def-up").css("margin-right", Db - E + 3);
$("#game-position-def-down").css("width", E);
$("#game-position-def-down").css("height", Db);
$(".game-selection-card-image").css("width", E);
zb && $c();
}
window.qf = function qf(a, b) {
if(listeners["targetCardAnimation"]) {
for(let cb of listeners["targetCardAnimation"]) {
cb(a.code);
}
}
let originalZ = a.a.css("z-index");
a.a.css("z-index", 10000)
.css("animation", "fullScale " + (600 * C) + "ms");
a.a.animate({
opacity: .5
}, {
duration: 100 * C
}).animate({
opacity: 1
}, {
duration: 100 * C
}).animate({
opacity: .5
}, {
duration: 100 * C
}).animate({
opacity: 1
}, {
duration: 100 * C
}).animate({
opacity: .5
}, {
duration: 100 * C
}).animate({
opacity: 1
}, {
duration: 100 * C,
complete: function () {
a.a.css("animation", "")
.css("z-index", originalZ);
if(b) {
b();
}
}
});
};
window.df = function df(a, b, c, d, e) {
if(listeners["cfReveal"]) {
for(let cb of listeners["cfReveal"]) {
cb(b);
}
}
var g = a.a.offset(),
k = a.location & O.j || c & 5 ? b : 0,
w = hg(a.controller, a.location, c) - a.va,
F = false;
if(a.Kb !== k) {
F = true;
}
if(null !== a.b) {
a.b.hide();
a.K.hide();
}
a.code = b;
a.position = c;
$("<div />").animate({
height: 1
}, {
duration: d,
step: function(b, c) {
b = c.pos;
c = "translate(";
c += (a.ta.left - g.left) * (1 - b);
c += "px, ";
c += (a.ta.top - g.top) * (1 - b);
c += "px)";
c += " rotate(" + (a.va + w * b) + "deg)";
if(F) {
if(.5 < b) {
ig(a, k);
}
c += " scalex(" + Math.abs(1 - 2 * b) + ")";
}
a.a.css("transform", c)
},
complete: function() {
null !== a.b && (a.b.show(), a.K.show());
a.a.css("position",
"");
nf(a);
e()
}
})
}
// re-add listener
// remove current resize listener
// $(window).off("resize", Vb);
// $(window).resize(Vb);
Fb.ChatMessageReceived = window.qd = displayOpponentsMessage;
console.info("ChatImprovements plugin loaded!");
//
let overlayExtension;
$(".game-field-zone").on("mouseover", function (ev) {
let player = $(this).data("player");
let location = $(this).data("location");
let index = $(this).data("index");
let card = T(player, location, index);
if(!card) return;
let overlays = card.l;
if(!overlayExtension) {
overlayExtension = $("<p id=game-tooltip-overlay-extension></p>");
$("#game-tooltip .card-if-monster").append(overlayExtension);
}
if(overlays && overlays.length) {
$(overlayExtension).empty();
let { width, height } = this.querySelector("img");
console.log("width, height:", width, height);
let plural = overlays.length === 1 ? "" : "s";
let msg = "[" + overlays.length.toString() + " material" + plural + "]\n";
$(overlayExtension).append($("<p>" + msg + "</p>"));
for(let overlay of overlays) {
let imgSrc = ra(overlay.code);
let img = $("<img class=material-preview src='" + imgSrc + "' width=" + width + " height=" + height + ">");
// img.width = width;
// img.height = height;
$(overlayExtension).append(img);
}
$(overlayExtension).show();
}
else {
$(overlayExtension).hide();
}
});
$(".game-field-zone").on("mouseout", function (ev) {
$(overlayExtension).hide();
});
};
waitForElementJQuery("#game-room-container:visible, #game-field:visible").then(() => {
onload();
});
// on-load stuff