User script: Difference between revisions

From GreaseSpot Wiki
Jump to navigationJump to search
No edit summary
m spam
Line 1: Line 1:
// ==UserScript==
{{stub}}
// @name          Travian Building Mover
// @namespace      Travian Building Mover
// @description    This repositions the buildings on the dorf2.php page
// @version        1.5.1
// @include        http://*.travian.*/dorf2.php*
// @license        GPL 3 or any later version
// ==/UserScript==


/*****************************************************************************
'''User scripts''', or '''userscripts''', are scripts that make on-the-fly changes to specific web pages on the client side (in the browser or a proxy server), typically to change their appearance or to add or modify functionality.
* Copyright (C) 2009 Adriaan Tichler
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Public License for more details
*
* To obtain a copy of the GNU General Public License, please see
* <http://www.gnu.org.licenses/>
*****************************************************************************/


// First, get the user mappings...
User scripts for [[Greasemonkey]] and Greasemonkey-compatible alternatives are written in [http://developer.mozilla.org/en/docs/JavaScript JavaScript], but there is at least one example of using another scripting language, namely Ruby in [http://github.com/why/mousehole/tree/master/ MouseHole].
var mapping = eval(GM_getValue('mapping', '({})'));


function reset_vil(){
For tools other than Greasemonkey that apply user scripts to web sites, see [[Cross-browser_userscripting|Cross-browser Userscripting]] and [http://en.wikipedia.org/wiki/Greasemonkey#Compatibility Wikipedia].
    if (!window.confirm("Reset this village's buildings to their original position?")) return;
    delete mapping[did];
    GM_setValue('mapping', uneval(mapping));
    location.reload();
}
 
// Register these first, in case the script fails later and we still want to reset things
GM_registerMenuCommand("BM: Reset this village's buildings", reset_vil);
GM_registerMenuCommand("BM: Reset all buildings", function(){
        if (!window.confirm("Reset all buildings in all villages to their original position?")) return;
        GM_setValue('mapping', '({})');
        location.reload();
    });
 
// Init
var server = location.host;
var uid = document.evaluate("id('side_navi')//a[contains(@href, 'spieler.php')]/@href", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent.match(/uid=(\d+)/)[1];
 
// Add support for the 'toggle building levels' button, so we can make it persistent
// Otherwise, this value keeps getting cleared whenever cookies get cleared, which for the more paranoid of us would be every time the browser restarts ;-)
var toggle = eval(GM_getValue('show_building_level', '({})'));
var button = document.getElementById('lswitch');
if (button != undefined){
    var current_toggle = button.className == "on";
    // If we don't have a saved setting for this server and user, then take the present value of the toggle
    if (toggle[server+'_'+uid] == undefined){
        toggle[server+'_'+uid] = current_toggle;
        GM_setValue('show_building_level', uneval(toggle));
    }
    // Otherwise, correct the value of the toggle to what we have saved
    // *note* calling vil_levels_toggle() in this fashion is safer than using unsafeWindow, because unsafeWindow would elevate the privilege of the function.
    else if (current_toggle != toggle[server+'_'+uid]) location.href = "javascript:void(vil_levels_toggle());";
 
    // Either way, add a listener to update our version of the toggle when it's clicked
    button.addEventListener('click', function(){
            toggle[server+'_'+uid] = !toggle[server+'_'+uid];
            GM_setValue('show_building_level', uneval(toggle));
        }, false);
}
 
// Look at where the original buildings are *first*
var data = [];
var poly = document.getElementById('map2').childNodes;
var img = document.getElementById('map2').nextSibling.nextSibling.childNodes;
 
// Raw_num won't have the right number of elements if there are unused building spots in the village
var num = [];
var raw_num = document.getElementById('village2_levels');
// Some servers use a different ID...
if (raw_num == undefined) raw_num = document.getElementById('levels');
if (raw_num != undefined){
    raw_num = raw_num.childNodes;
    for (var i in raw_num){
        if (raw_num[i].className == undefined || raw_num[i].className.indexOf('level') >= 0) continue; // Don't do walls, closing divs, or the rally point
        num[raw_num[i].className.split('d')[1] - 0] = raw_num[i]; // re-index these nodes so they don't get mistakenly translated by an empty spot
    }
}
 
// Store the current info about all of the buildings...
for (var i=1; i <= 20; i++){
    data[i] = [];
    //GM_log(i + ' ' + img[i].alt + ' | ' + poly[i].title);
 
    data[i]['className'] = img[i].className.split(' ')[2];
    if (num[i] != undefined) data[i]['num'] = num[i].className;
 
    data[i]['title'] = poly[i].title;
    data[i]['href'] = poly[i].href;
}
 
// Get the active village, to store the new mappings
// We don't have to worry about postfixes because we're only running on one page
var did = document.evaluate('//tr[@class="sel"]/td[@class="text"]/a', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if (did) did = did.href.match('newdid=([0-9]*)')[1];
else {
    // If this fails, there's a possibility that we're just running the other type of travian (??? still 3.5, but with different code...)
    did = document.evaluate('//table[@id="vlist"]/tbody/tr/td[@class="dot hl"]', document, null, XPathResult.ANY_UNORDERED_NODE_TYPE,null).singleNodeValue;
    if (did) did = did.parentNode.innerHTML.match('newdid=([0-9]*)')[1];
}
// Single village support courtesy of Booboo
if (!did) {
    var single_villages = eval(GM_getValue('single_villages', '({})'));
    if (!single_villages[server + "_" + uid]){
GM_xmlhttpRequest({
                method: 'GET',
                url: "http://" + server + "/dorf3.php",
                onload: function(xhr){
                    var did = xhr.responseText.match(/newdid=(\d+)/)[1];
                    single_villages[server + "_" + uid] = did;
                    GM_setValue('single_villages', uneval(single_villages));
                    window.location.reload();
                }
            });
        return;
    }
    else did = single_villages[server + "_" + uid];
}
 
if (mapping[did] == undefined) mapping[did] = {};
 
// This moves a building from src to dest.
function move(dest, src){
    //GM_log('Moving '+src+' to '+dest);
    var base = img[dest].className.split(' '); // We only change the last part of the class name
    img[dest].className = base[0]+' '+base[1]+' '+data[src].className;
 
    if (num[src] != undefined) num[src].className = 'd'+dest; // Move the building numbers. This goes backwards from everything else...
 
    poly[dest].title = data[src].title;
    poly[dest].href = data[src].href;
}
 
// The index is the destination, the value the source
for (var i in mapping[did]) move(i, mapping[did][i]);
 
// Get input from the user... add the moving truck.
var div = document.createElement('div');
div.setAttribute('style', 'position:absolute; top:489px; left:163px; padding:2px; z-index:100; border:none; cursor:pointer');
div.innerHTML = '<img title="Swap Buildings" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QCURXhpZgAASUkqAAgAAAABAGmHBAABAAAAGgAAAAAAAAABAIaSBwBgAAAALAAAAAAAAABBU0NJSQAAAFdpbmRvd0V4dDogMzAzNSwgMjY3NA1XaW5kb3dPcmc6IDAsIDANQ29udGVudDogMTAsIDI2LCAzMDEyLCAyNjcyDUlnbm9yZWQgT3Bjb2RlczoNJDEwNQD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAcACEDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAcIBgED/8QAMRAAAgIBAwMCAwUJAAAAAAAAAQIDBAUGERIABxMhMQgVFxQiMmGUIzRRUlNWcZHS/8QAGAEBAAMBAAAAAAAAAAAAAAAABQAEBgH/xAAkEQABAwMDBAMAAAAAAAAAAAABAAIDBBExEiEiBRRRYUFSwf/aAAwDAQACEQMRAD8AoP4khmPoxqF8FlbmJvRRxSpbqTtDLEqTxtIVdSCPuBh+e/UNyYPW8unY83FqS/NesTeCpG1mQ2rTjcSEFSTupjb3A9Nt2I2DXN3uzWLl7Sa2px2uVk4G+EVY2P3xBJt7D+PUZZm/Rg7lYiOu9z5LirMzJY8TVuAmaWWX9oxU7gsoB5KNh6b9F175w5ojxuceFcpGsJ5Khuxd7WmE0hJmEzGd1VjPmVmGShkyzXEhifxcq7OeXNWjfeF2Kt6cSjDZ35iMlQzGMr5PHTpYqWI/JFIu+zL/AIPqD+R9R0kex+pdOVu2tQ2M5jqvK/kZeNi+hYK96wykuWPL0P4tzv779ZrSmu27e5HIaiuajqZTT2dyd94MYbpHgX7XMyzQMzuhaVWJEYESMCrEjg7HL9F6/UPrZ6asHFruBsd/WLbeVJ4m5Yqe4j+dv99HWJ+o+nP6l79M/wD10dbfu4fsqtnrHfEm+PuURpDGN5NT5pAVroRwirhwWsTggjx7rwCkHy7lOLDmVUGL7ZrrCtFofQjY6pisFMnzPMT0o53uWVIYxBSNnCkqWDNsAVADbb9eT53J2e8Wd00bLRS5vUjUrWXT9+WE2jCqo53RQkahVHDYe+2/r1V2h9M4XSWHjweCpitSqjxxruWYj8RLMfUks7Ek+5Y9IEiOK4y5BxskrKxz3u4RYHk/JP4oqxvw0d6slnaz5VcNQr17CFZRPD4I039WjhjHEbbctuI3J3I39enlW+FrSlqtTj1RqDMZZqcgKGAmBZYw0hIlVjJzdg4VnUo2yLx4kEmhB109HljL3tum9RS/+jHa3+wdO/oV6Ot90dTX6XdRX//Z">';
document.body.appendChild(div);
 
function notify(msg){
    var div = document.createElement('div');
    div.setAttribute('style', 'position:absolute; top:350px; left:400px; padding:2px; z-index:160; border:solid black 1px; background:#fff; -moz-border-radius:5px;');
    div.innerHTML = msg;
    document.body.appendChild(div);
 
    window.setTimeout(function(){div.parentNode.removeChild(div);}, 2000);
}
 
var truck_stage = 0;
div.addEventListener('click', function(){
        // If the truck gets clicked a second time...
        if (truck_stage == 1){
            reset_vil();
            return;
        }
        truck_stage++;
        div.childNodes[0].title = 'Restore building positions';
 
        // Add listeners to all of the objects
        var stage = 0;
        var src;
 
        // Cut all of the village links, so clicking on the villages no longer redirects
        // Also, store index info in here - it's the easiest way I can think of getting this info to the click listener routine
        for (var i in poly)
            if (poly[i].href != undefined)
                poly[i].href = '#'+(poly[i].href.split('id=')[1] - 18);
        var wall = document.getElementById('map1').childNodes;
        for (var i in wall)
            if (wall[i].href != undefined)
                wall[i].href = '#22';
 
        // Listen for a click on each building
        for (var i in poly) poly[i].addEventListener('click', function(e){
                var dest = e.target.href.split('#')[1]; // Extract the index info from above
 
                // Error conditions
                if (dest == '21'){
                    notify('<b>You cannot move the rally point</b>');
                    return;
                }
                if (dest == '22'){
                    notify('<b>You cannot move the walls</b>');
                    return;
                }
 
                // This is the first click
                if (stage == 0){
                    src = dest; // actually...
 
                    notify('<b>Click on the second one</b>');
                    stage++;
                } else { // Now we have to save said data
                    var m = mapping[did];
 
                    //GM_log('src='+src+' dest='+dest);
                    // First, find who *holds* src right now
                    var temp = src;
                    while (m[temp] != undefined && m[temp] != src) temp = m[temp];
                    // Find who *holds* dest right now
                    var temp2 = dest;
                    while (m[temp2] != undefined && m[temp2] != dest) temp2 = m[temp2];
                    //GM_log('m['+temp+']='+dest);
                    //GM_log('m['+temp2+']='+src);
                    m[temp] = parseInt(dest);
                    m[temp2] = parseInt(src);
 
                    GM_setValue('mapping', uneval(mapping));
                    window.location.reload();
                }
            }, false);
 
        notify('<b>Click on the first building</b>');
    }, false);

Revision as of 12:22, 10 February 2010


User scripts, or userscripts, are scripts that make on-the-fly changes to specific web pages on the client side (in the browser or a proxy server), typically to change their appearance or to add or modify functionality.

User scripts for Greasemonkey and Greasemonkey-compatible alternatives are written in JavaScript, but there is at least one example of using another scripting language, namely Ruby in MouseHole.

For tools other than Greasemonkey that apply user scripts to web sites, see Cross-browser Userscripting and Wikipedia.