﻿  var userAgent = navigator.userAgent.toLowerCase();
  var is_opera = (userAgent.indexOf('opera') != -1);
  var is_safari = ((userAgent.indexOf('applewebkit') != -1) || (navigator.vendor == "Apple Computer, Inc."));
  var is_webtv = (userAgent.indexOf('webtv') != -1);
  var is_ie = ((userAgent.indexOf('msie') != -1) && (!is_opera) && (!is_safari) && (!is_webtv));
  var is_ie4 = ((is_ie) && (userAgent.indexOf("msie 4.") != -1));
  var is_ie6 = ((is_ie) && (userAgent.indexOf("msie 6.") != -1));
  var is_mozilla = ((navigator.product == 'Gecko') && (!is_safari));
  var is_firefox = (is_mozilla && userAgent.indexOf('irefox') != -1);
  var is_konqueror = (userAgent.indexOf('konqueror') != -1);
  var is_ns = ((userAgent.indexOf('compatible') == -1) && (userAgent.indexOf('mozilla') != -1) && (userAgent.indexOf('netscape') != -1) && (!is_opera) && (!is_webtv) && (!is_safari));
  var is_ns4 = ((is_ns) && (parseInt(navigator.appVersion) == 4));

  var notesShown = false;
  var XHR1 = new xHttpRequest();				// Erstelle HTTP Request Object
  var menuLeft = true;
  var reloadNotes = true;
  var abortNotepadDisplay = false;
  var lastX = -1;
  var lastY = -1;
  var endzeit = undefined;
  var menuStringDefault = '';
  var useGrafikpfad = 'images/de/grafikpack-full';
  var usergroupsToStrings = $H({'user':'?','group':'Gruppename/Kürzel','Support':'Support'});
  mainObjectId = 'dl4All';
  var activePopup = false;
  
  /**
    * Funktion, die alles was zur DL4-Seite gehört vorbereitet
    */
  function launchDL4() {
    window.setInterval(dl4Queue, 1000);
    setupKeys();				// Erstelle Tastenkürzel
    prepareMainMenu();			// Bereite Hauptmenü vor
    prepareButtons();			// Bereite Buttons vor
    prepareBuildings();			// Bereite Gebäude vor
    prepareTooltips();			// Bereite Tooltips vor
    //window.setInterval(scrollFixedObjs, 250);
    Event.observe(window, 'scroll', scrollFixedObjs);
  }
  
  /**
    * Scrollt Objekte zum entsprechenden Punkt, falls gescrollt wird (als ersatz für die CSS position: fixed, da sie oft schlecht interpretiert wird und der Firefox Geschwindigkeitsprobleme hat mit fixed Objekten)
    */
  function scrollFixedObjs() {
    var curY = xScrollTop();		// Hole aktuelle Scrollposition
    var curX = xScrollLeft();		// Hole aktuelle Scrollposition
    if(curY != lastY || curX != lastX) { // Schaue ob sich die Scrollposition geändert hat und wenn ja
      var menu = $('dl4MainMenu');		// Hole zu scrollende Objekte
      var eggs = $('dl4Eggs');
      var toparea = $('dl4TopArea');
      if(lastX == -1) {					// Falls die Seite gerade gelesen wurde, notieren wir mal, wo die Objekte eigentlich sein sollten
      	menu.basicX = xLeft(menu); menu.basicY = xTop(menu);	// Speichere fixed Koordinaten des Hauptmenüs
      	if(eggs) { eggs.basicX = xLeft(eggs); eggs.basicY = xTop(eggs); }	// Speichere fixed Koordinaten des Eiermenüs, falls existent
      }
      //xSlideTo(toparea, xLeft(toparea), curY, (lastY > curY || lastY == -1 ? 0 : 200));
      lastY = curY;				// Speichere die neue Scrollposition
      lastX = curX;
      if(!menu.noScroll) {
      	xSlideTo(menu, lastX + menu.basicX, lastY + menu.basicY, 200); // Bewege Objekte zum neuen Scrollpunkt
        if(eggs) xSlideTo(eggs, lastX + eggs.basicX, lastY + eggs.basicY, 200);
      }
      
    }
  }
  
  function advertise() {
    var ad = $('dl4Ads');
    if(ad) {
      ad.innerHTML = '<iframe src="werbung/werbung.php" width="468" height="60" name="Gallendor Werbung" scrolling="no" marginheight="0" marginwidth="0" frameborder="0"></iframe>';
    }
  }

  /**
    * Richte Tastenkürzel für DL ein
    */
  function setupKeys() {
    if(String(window.location.href).indexOf('?location=igm&sub=neu') != -1 && String(window.location.href).indexOf('sent=yes') == -1) return; // Im "IGM schreiben"-Fenster sind wir mal so frei und deaktivieren die Shortcuts. Wenn die IGM danach versendet wurde, können wir wieder die Shortcuts nutzen

    shortcut.add("A", function() { location.href='?location=kaserne'; });
    shortcut.add("B", function() { location.href='?location=bibliothek'; });
    shortcut.add("C", function() { location.href='?location=schattenportal'; });
    shortcut.add("D", function() { location.href='?location=bauten'; });
    shortcut.add("E", function() { location.href='?location=einheiten'; });
    shortcut.add("F", function() { location.href='?location=friedhof'; });
    shortcut.add("G", function() { location.href='?location=group'; });
    shortcut.add("H", function() { location.href='?location=help'; });
    shortcut.add("I", function() { location.href='?location=sonst'; });
    shortcut.add("K", function() { location.href='?location=karte'; });
    shortcut.add("L", function() { location.href='?location=tempel'; });
    shortcut.add("M", function() { location.href='?location=markt'; });
    shortcut.add("N", function() { location.href='?location=igm'; });
    shortcut.add("O", function() { location.href='?location=drachenhof'; });
    shortcut.add("R", function() { location.href='?location=ressourceinfo'; });
    shortcut.add("S", function() { location.href='?location=tavern&action=search'; });
    shortcut.add("T", function() { location.href='?location=truppen'; });
    shortcut.add("U", function() { location.href='?location=tribunal'; });
    shortcut.add("V", function() { location.href='?location=verteidigung'; });
    shortcut.add("W", function() { location.href='?location=wappen'; });
    //shortcut.add("X", function() { location.href='?location=hexenkueche'; });
    shortcut.add("Q", function() { location.href='http://forum.gallendor.com'; });
    shortcut.add("1", function() { location.href= $('chSettle1').getAttribute('href'); });
    shortcut.add("2", function() { var ch2 = $('chSettle2'); if(ch2) { location.href= ch2.getAttribute('href'); } });
  }

  /**
    * Bereite Statusnachrichten-Fenster vor
    */
  function prepareStatusMsgWindow(idSuffix) {
    enableDragWithHelper('dl4StatusMover' + idSuffix, 'dl4Status' + idSuffix, null, function() { checkAndSavePosition('dl4Status', 6); }); // Ermögliche das Ziehen des Statusfensters
    var statusContent = $('dl4StatusContent' + idSuffix);		// Hole den Inhalt des Statusbereichs
    $('dl4Status' + idSuffix).insertBefore(makeAbortButton('dl4Status' + idSuffix, 'dl4StatusClose' + idSuffix), statusContent);
    var markRead = $('dl4MarkStatusRead' + idSuffix);
    if(markRead) {
      enableHoverImageDL('dl4MarkStatusRead' + idSuffix);
      if(idSuffix == '') {
        Event.observe('dl4MarkStatusRead' + idSuffix, 'click', markStatusRead);
      } else {
      	Event.observe('dl4MarkStatusRead' + idSuffix, 'click', new Function('deleteNodeById(\'dl4Status' + idSuffix + '\');'));
      }
    }
    if(statusContent.hasChildNodes() && statusContent.childNodes.length > 1) { // Falls mehr als eine Statusnachricht vorhanden sind
      enableHoverImageDL('dl4NextStatusmsg' + idSuffix, 'dl4PreviousStatusmsg' + idSuffix); // Ermöglich Hovering bei den Next/Prev-Buttons
      var nextImg = $('dl4NextStatusmsg' + idSuffix), prevImg = $('dl4PreviousStatusmsg' + idSuffix); // Hole die Buttons
      xShow(nextImg);						// Zeige den Next-Button (schliesslich haben wir mehr als eine Statusnachricht)
      Event.observe(nextImg, 'click', showNextStatusmsg);	// Aktiviere Funktionalität des Next-Buttons
      Event.observe(prevImg, 'click', showPrevStatusmsg);	// Aktiviere Funktionalität des Previous-Buttons
      activeStatusmsg = statusContent.firstChild;		// Zu Beginn ist die aktive Statusnachricht die erste
      activeStatusmsg.idSuffix = idSuffix;
    }
  }

  function speedupWindow(elem, jobId) {
    var thePopup = $('speedup' + String(jobId));
    if(!thePopup) {
      thePopup = new Element('div', { 'id' : 'speedup' + String(jobId) });
      thePopup.setStyle({'width' : '250px', 'height' : '200px'}).addClassName('hidden');
      $('dl4All').insert(thePopup);
    }
    new Ajax.Updater(thePopup, 'actions.php', { 'method': 'get', 'evalScripts' : true, 'parameters': {'location': 'speedup', 'job' : jobId, 'noxml' : 'yes'}});
    return(showPopup(elem, thePopup));
  }
  
  function updateSpeedupData(jobId, maxTime) {
    var tenMinutes = parseInt($('speedup' + String(jobId) + 'Val').value, 10);
    $('speedup' + String(jobId) + 'Time').update(seconds_to_countdown((maxTime - tenMinutes) * 600));

    var theDiscount = 0;			// No discount by default
    var theColor = '#e53f09';			// Warning red for no discount
    
    if(tenMinutes > 60) {
      var theDiscount = 50;
      var theColor = '#9eeb0a';
    } else if(tenMinutes > 36) {
      var theDiscount = 25;
      var theColor = '#fff410';
    } else if(tenMinutes > 18) {
      var theDiscount = 10;
      var theColor = '#ff9f0d';
    }

    $('speedup' + String(jobId) + 'Cost').update(Math.ceil(tenMinutes * (100 - theDiscount) / 100));
   
    $('speedup' + String(jobId) + 'Discount').update(theDiscount).setStyle({ 'color' : theColor});
  }
  
  function markStatusRead() {
    if(XHR1.status != XHR1.NOXMLOBJ) {				// Falls asynchrone Requests erlaubt werden
      if(XHR1.busy) {							// Falls das Request-Objekt noch arbeitet
        setTimeout(markStatusRead, 250);					// Starten wir diese Funktion in 250ms erneut
      } else {								// Falls das Request-Objekt nicht mehr arbeitet
      	var curDate = new Date();
        if(XHR1.send('GET', 'actions.php', 'location=status&action=markstatusread&curtime=' + curDate.getTime(), 15000, false, false, false, false)) {
          xStyle('display', 'none', 'dl4Status');
          return(false);
        } else {
          location.href = '?location=status&action=markstatusread';
        }
      }
    }
  }
  
  function showNextStatusmsg(ev) {
    if(activeStatusmsg.nextSibling) {
      xStyle('display', 'none', activeStatusmsg);
      var idSuffix = activeStatusmsg.idSuffix;
      activeStatusmsg = activeStatusmsg.nextSibling;
      activeStatusmsg.idSuffix = idSuffix;
      xStyle('display', 'block', activeStatusmsg);
      if(!activeStatusmsg.nextSibling) xHide('dl4NextStatusmsg' + idSuffix);
      xShow('dl4PreviousStatusmsg' + idSuffix);
    }
  }
  
  function showPrevStatusmsg(ev) {
    if(activeStatusmsg.previousSibling) {
      xStyle('display', 'none', activeStatusmsg);
      var idSuffix = activeStatusmsg.idSuffix;
      activeStatusmsg = activeStatusmsg.previousSibling;
      activeStatusmsg.idSuffix = idSuffix;
      xStyle('display', 'block', activeStatusmsg);
      if(!activeStatusmsg.previousSibling) xHide('dl4PreviousStatusmsg' + idSuffix);
      xShow('dl4NextStatusmsg' + idSuffix);
    }
  }
  
  /**
    * Bereite alle Tooltips und Fehlermeldungen vor, die mit der entsprechenden Klasse erstellt wurden
    */
  function prepareTooltips() {
    var tt1 = $('dl4AllTooltips');				// Hole das wirkliche Tooltip-Inhalt-DIV
    var tt2 = $('dl4AllTooltips2');				// Suche das Element, dass zusätzliche Tooltips enthalten kann
    if(tt2) {							// Falls das Element existiert
      while(tt2.hasChildNodes()) {				// Hänge alle Kindknoten des zusätzlichen Elements an den wirklichen Tooltip-Behälter, falls sie keine Textknoten sind, sonst lösche sie
      	if(tt2.firstChild.nodeType != 3) tt1.appendChild(tt2.firstChild);
      	else(tt2.removeChild(tt2.firstChild));
      }
    }
    var tooltipDivs = tt1.childNodes;

    var bm = $('dl4BuildMain');
    var bml = 0; bmt = 0;
    if(bm) {
      bml = xPageX(bm); bmt = xPageY(bm);
    }

    for(var i = 0, len = tooltipDivs.length; i < len; ++i) {	// Gehe alle Tooltips durch
      var curTooltip = xGetElementById(tooltipDivs[i].id.substr(3));	// Hole das Element, bei dessen Berührung dieses Tooltip angezeigt werden soll
      if(curTooltip) {							// Falls das Tooltip gefunden wurde
      	if(tooltipDivs[i].className.indexOf('Build') != -1) {
      	  curTooltip.isFixed = true;
      	  xLeft(tooltipDivs[i], bml);
      	  xTop(tooltipDivs[i], bmt - xHeight(tooltipDivs[i]));
      	  xStyle('display', 'none', tooltipDivs[i]);
      	  xShow(tooltipDivs[i]);
      	} else {
      	  curTooltip.isFixed = false;
      	}
      	curTooltip.ttId = tooltipDivs[i].id;					// Speichere den Tooltip-div-Namen in einer Eigenschaft
      	Event.observe(curTooltip, 'mouseover', showTT);				// Notiere als onmouseover-Event das Anzeigen des Tooltips
      	Event.observe(curTooltip, 'mouseout', hideTT);				// Notiere als onmouseout-Event das Ausblenden des Tooltips
      }
    }

    bm = $('dl4AllErrors');					// Schaue ob Fehler/Erfolgsmeldungen generiert wurden
    if(bm) {							// Falls Fehler/Erfolgsmeldungen generiert wurden
      var errorWin = infoWindow('', 'dl4ErrorWin');
      errorWin.lastChild.appendChild(bm);
    }
    
    $(document).observe('click', function(ev) { var ce = Event.element(ev); if(!ce.id || (typeof(activePopup) != 'undefined' && ce.id.indexOf(activePopup.id) == -1)) hideActivePopup(); }); // Observe clicks outside popups and close the popup if necessary

  }
  
  /**
    *
    */
  function addTooltip(elemId, tooltipText) {
    var curTooltip = $(elemId);			// Hole das Element, bei dessen Berührung ein Tooltip angezeigt werden soll
    if(curTooltip) {							// Falls das Tooltip gefunden wurde
      var ttDiv = new Element("div", { "id" : "tt_" + elemId, "class" : "dl4Tooltip" }).update(tooltipText);
      $('dl4AllTooltips').appendChild(ttDiv);
      curTooltip.isFixed = false;
      curTooltip.ttId = ttDiv.id;						// Speichere den Tooltip-div-Namen in einer Eigenschaft
      Event.observe(curTooltip, 'mouseover', showTT);				// Notiere als onmouseover-Event das Anzeigen des Tooltips
      Event.observe(curTooltip, 'mouseout', hideTT);				// Notiere als onmouseout-Event das Ausblenden des Tooltips
    }
  }
  
  /**
    * Show popup with the given id
    */
  function showPopup(elem, popup, elemOffset) {
	if(activePopup != false) hideActivePopup();
	activePopup = $(popup);
	elem = $(elem);
	if(elemOffset == undefined || elemOffset === false) {
		elemOffset = elem.cumulativeOffset();
		elemOffset.left = (elemOffset.left + activePopup.getWidth() + 50 > $(document).viewport.getWidth() ? elemOffset.left - activePopup.getWidth() : elemOffset.left);
		elemOffset.top = elemOffset.top + 8 + elem.getHeight();
    	}
	var useLeft = (elemOffset.left + activePopup.getWidth() + 50 > $(document).viewport.getWidth() ? elemOffset.left - activePopup.getWidth() : elemOffset.left);
	activePopup.removeClassName('hidden').hide().addClassName('popupActive').setStyle({left: elemOffset.left + 'px', top: elemOffset.top + 'px'}).appear({ duration: 0.25 }); // Show popup, position it
	return(false);
  }
  
  /**
    * Hide popup with the given id
    */
  function hideActivePopup() {
    if(activePopup != false) {
      activePopup.addClassName('hidden').removeClassName('popupActive').setStyle({'left':'', 'top' : ''});
      activePopup = false;
    }
    return(false);
  }
  
  /**
    * Item shop functions
    */
  function prepareShopItemCategory(category) {
  	currentShopItemPage = 1;
  }
  
function hoverShopItem(elem) {
	$(elem).addClassName('shopItemHovered');
}

function unhoverShopItem(elem) {
	$(elem).removeClassName('shopItemHovered');
}
  
  /**
    * Switch to next page
    */
  function nextShopItemPage() {
  	var nextPage = $('shopItemPage' + String(currentShopItemPage + 1)); // Check if there is a second page
  	if(nextPage) {					// If there is a page
  		$('shopItemPage' + String(currentShopItemPage)).fade({ duration: 0.2}); // Fade current page out
  		currentShopItemPage += 1;			// Increase page counter
  		nextPage.appear({ duration: 0.2});		// Show next page
  		$('currentPage').update(currentShopItemPage);	// Update page number indicator
  		$('previousShopItem').show();			// Show the link to the previous page (even if already shown)
  		nextPage = $('shopItemPage' + String(currentShopItemPage + 1)); // Check if there is even now a next page
  		if(!nextPage) $('nextShopItem').hide();		// If there is no next page, hide the next page link
  	}
  }
  
  function previousShopItemPage() {
  	if(currentShopItemPage > 1) {				// Only go to the previous page if we are not on the first one
  		$('shopItemPage' + String(currentShopItemPage)).fade({ duration: 0.2}); // Fade current page out
  		currentShopItemPage -= 1;			// Decrease page counter
  		$('shopItemPage' + String(currentShopItemPage)).appear({ duration: 0.2}); // Show previous page
  		$('currentPage').update(currentShopItemPage);	// Update page number indicator
  		$('nextShopItem').show();			// Show the link to the next page (even if already shown)
  		if(currentShopItemPage == 1) $('previousShopItem').hide(); // If we are on the first page, hide the previous page link
  	}
   }
  

  /**
    * Bereite Buttons vor
    */
  function prepareButtons() {
    /* Standardbuttons highlighten und wir vergeben außerdem 20 freie IDs, unter denen Hover-Buttons zu finden sein können */
    enableHoverImageDL('psearch', 'mysettings', 'mybuddies', 'myxtaorchat', 'dl4Minimizer', 'dl4Maximizer', 'dl4Logout', 'mynotes', 'myquests', 'myquestions', 'mynews', 'myminigame', 'dl4Queueify', 'mysirris', 'menu_premium', 'menu_forum',
    'hb01', 'hb02', 'hb03', 'hb04', 'hb05', 'hb06', 'hb07', 'hb08', 'hb09', 'hb10', 'hb11', 'hb12', 'hb13', 'hb14', 'hb15', 'hb16', 'hb17', 'hb18', 'hb19', 'hb20');

    Event.observe('dl4ResBar', 'click', function() { location.href = '?location=ressourceinfo'; });
    //Event.observe('dl4Queueify', 'click', function() { return(dl4Queueify()); });
    if($('dl4Minimizer')) Event.observe('dl4Minimizer', 'click', hideMainContent);
    Event.observe('dl4Maximizer', 'click', showMainContent);
    Event.observe('dl4Logout', 'click', function() { location.href = '?location=logout'; });

    var dl4MainMenu = $('dl4MainMenu');
    if(xLeft(dl4MainMenu) >= xClientWidth() || xTop(dl4MainMenu) >= xClientHeight()) xMoveTo(dl4MainMenu, 0, 150);
    if(xLeft('dl4Queue') >= xClientWidth()) xLeft('dl4Queue', xClientWidth() - 10 - xWidth('dl4Queue'));
    //enableDragWithHelper('dl4MainMenuTop', 'dl4MainMenu', null, updateMainMenuPosition);
    //enableDragWithHelper('dl4QueueTop', 'dl4Queue', function() { if(xLeft('dl4Queue') == 0) xLeft('dl4Queue', xPageX('dl4Queue')); }, function() { savePosition(3, xLeft('dl4Queue') - xScrollLeft(), xTop('dl4Queue') - xScrollTop()); });

    sizeLinkList()

  }
  
  function sizeLinkList() {
    var linkList = $('dl4Linklist');
    if(linkList) {
      var sum = 0;
      for(var i = 0, len = linkList.childNodes.length; i < len; ++i) {
      	sum += xWidth(linkList.childNodes[i]);
      }
      xWidth(linkList, sum + 10);
      //xLeft(linkList, Math.floor((xWidth(linkList.parentNode) - sum) / 2));
      //xShow(linkList);
      xHeight(linkList, 43);
    }
  }
  
  /**
    * DL4 queueifizieren
    */
  function dl4Queueify() {
    var fenster = window.open('queueify.php', 'DL4','scrollbars,width=186,height=300,left=200,top=200,resizable=yes,status=no,menubar=no,toolbar=no');
    fenster.focus();
    return(false);
  }

  /**
    * Nach dem Verschieben des Hauptmenüs wird die Position geprüft und die neue Position gespeichert
    */
  function updateMainMenuPosition() {
    var mm = $('dl4MainMenu');
    if(xPageX(mm) > xClientWidth() - 500) {	// Falls das Menü sich rechts befindet
      if(menuLeft) {						// Falls das Menü bisher links war
        reverseMainMenus();						// Müssen wir die Elemente umdrehen
      }
    } else if(!menuLeft) {				// Falls sich das Menü links befindet und es vorher rechts war
      reverseMainMenus();					// Müssen wir die Elemente umdrehen
    }
    var lmm = xLeft(mm); var tmm = xTop(mm);
    mm.basicX = lmm; mm.basicY = tmm;
    savePosition(1, lmm - xScrollLeft(), tmm - xScrollTop());
  }

  /**
    * Speichert die Position des übergebenen Objektes in der Ansichtstabelle des Users
    */
  function savePosition(typeId, leftPos, topPos, elemWidth, elemHeight) {
    var curDate = new Date();
    if(XHR1.status != XHR1.NOXMLOBJ) {				// Falls asynchrone Requests erlaubt werden
      if(XHR1.busy) {							// Falls das Request-Objekt noch arbeitet
        setTimeout(function() { savePosition(typeId, leftPos, topPos); }, 250); // Starten wir diese Funktion in 250ms erneut
      } else {							// Falls das Request-Objekt nicht mehr arbeitet
        if(XHR1.send('GET', 'actions.php', 'location=status&action=saveposition&saveelem=' + String(typeId) + '&x=' + String(leftPos) + '&y=' + String(topPos) + (xDef(elemWidth) ? '&width=' + String(elemWidth) + '&height=' + String(elemHeight) : '') + '&curtime=' + curDate.getTime(), 15000, false, false, false, false)) {
          return(false);
        }
      }
    }
    /* Fallback, falls XMLHTTP-Requests nicht klappen: Popup-Fenster */
    //location.href = 'actions.php?location=status&action=saveposition&saveelem=' + String(typeId) + '&x=' + String(leftPos) + '&y=' + String(topPos) + '&curtime=' + curDate.getTime();
    return(false);
  }

  /**
    * Prüft, ob das gewünschte Element vielleicht VOR dem Werbebanner liegt (pöse!)
    */
  function checkAndSavePosition(elemId, positionId) {
    var ads = $('dl4Ads');		// Hole Werbeblock
    var res = $(elemId);		// Hole zu prüfendes Objekt
    var rl = xLeft(res);		// Hole Koordinaten des Objekts
    var rt = xTop(res);			// ...
    if(ads) {				// Falls der Spieler ein Werbebanner hat (kein PA)
      if(xIntersection(ads, res)) {
      	xLeft(res, 100);
      	xTop(res, 100);
      	return(infoWindow(I18N.wordTable['noObjInFrontOfAds'], 'warnResAds'));
      }
    }
    res.basicX = rl; res.basicY = rt; // Speichere neue Basiskoordinaten, damit beim die Ressourcen beim Scrollen auch bleiben wo sie sollen
    savePosition(positionId, rl - xScrollLeft(), rt - xScrollTop());
  }

  /**
    * Bereite Gebäude und Ihre Links vor
    */
  function prepareMainMenu() {
    var menu = $('dl4MainMenu');
    menu.noScroll = false
    if(xPageY(menu) + xHeight(menu) > xClientHeight()) {
      if($('dl4MenuBuildings')) xStyle('position', 'absolute', menu, 'dl4MenuBuildings', 'dl4MenuTraining', 'dl4MenuTrade', 'dl4MenuFighting', 'dl4MenuCommunity', 'dl4MenuOther');
      menu.noScroll = true;
    }
    if(!$('dl4MenuBuildings')) return;

    
    menuStringDefault = $('dl4MainMenuTop').innerHTML;
    enableMenuImages('menu_hh', I18N.getSpecificString('INFO_MENU_HH'), 'menu_settleshop', I18N.getSpecificString('INFO_MENU_SETTLESHOP'), 'menu_bibo', I18N.getSpecificString('INFO_MENU_BIBO'), 'menu_tempel', I18N.getSpecificString('INFO_MENU_TEMPEL'), 'menu_hexe', I18N.getSpecificString('INFO_MENU_HEXE'),
                       'menu_kaserne', I18N.getSpecificString('INFO_MENU_KASERNE'), 'menu_friedhof', I18N.getSpecificString('INFO_MENU_FRIEDHOF'), 'menu_drachenhof', I18N.getSpecificString('INFO_MENU_DRACHENHOF'), 'menu_schattenportal', I18N.getSpecificString('INFO_MENU_SCHATTENPORTAL'), 'menu_verteidigung', I18N.getSpecificString('INFO_MENU_VERTEIDIGUNG'),
                       'menu_markt', I18N.getSpecificString('INFO_MENU_MARKT'), 'menu_handel', I18N.getSpecificString('INFO_MENU_HANDEL'), 'menu_wappen', I18N.getSpecificString('INFO_MENU_WAPPEN'),
                       'menu_truppen', I18N.getSpecificString('INFO_MENU_TRUPPEN'), 'menu_einheiten', I18N.getSpecificString('INFO_MENU_EINHEITEN'), 'menu_karte', I18N.getSpecificString('INFO_MENU_KARTE'), 'menu_area', I18N.getSpecificString('INFO_MENU_AREA'),
                       'menu_gruppe', I18N.getSpecificString('INFO_MENU_GRUPPE'), 'menu_krieg', I18N.getSpecificString('INFO_MENU_KRIEG'), 'menu_toplist1', I18N.getSpecificString('INFO_MENU_TOPLIST1'), 'menu_toplist2', I18N.getSpecificString('INFO_MENU_TOPLIST2'), 'menu_toplistg', I18N.getSpecificString('INFO_MENU_TOPLISTG'),
                       'menu_igm', I18N.getSpecificString('INFO_MENU_IGM'), 'menu_hilfe', I18N.getSpecificString('INFO_MENU_HILFE'), 'menu_sonstiges', I18N.getSpecificString('INFO_MENU_SONSTIGES'), 'menu_tavern', I18N.getSpecificString('INFO_MENU_TAVERN'), 'menu_mitarbeiter', I18N.getSpecificString('INFO_MENU_COMMITMENT'), 'menu_turnier', I18N.getSpecificString('INFO_MENU_TOURNEY'));

    Event.observe('menu_hh', 'mouseover', function() { $('dl4MenuBuildings').active = true; displayMenuRow('menu_hh', 'dl4MenuBuildings'); })
    Event.observe('menu_hh', 'mouseout', function() { delayedMenuRowHide('dl4MenuBuildings'); })
    Event.observe('dl4MenuBuildings', 'mouseover', function() { $('dl4MenuBuildings').active = true; })
    Event.observe('dl4MenuBuildings', 'mouseout', function() { delayedMenuRowHide('dl4MenuBuildings'); })

    Event.observe('menu_kaserne', 'mouseover', function() { $('dl4MenuTraining').active = true; displayMenuRow('menu_kaserne', 'dl4MenuTraining'); })
    Event.observe('menu_kaserne', 'mouseout', function() { delayedMenuRowHide('dl4MenuTraining'); })
    Event.observe('dl4MenuTraining', 'mouseover', function() { $('dl4MenuTraining').active = true; })
    Event.observe('dl4MenuTraining', 'mouseout', function() { delayedMenuRowHide('dl4MenuTraining'); })

    Event.observe('menu_markt', 'mouseover', function() { $('dl4MenuTrade').active = true; displayMenuRow('menu_markt', 'dl4MenuTrade'); })
    Event.observe('menu_markt', 'mouseout', function() { delayedMenuRowHide('dl4MenuTrade'); })
    Event.observe('dl4MenuTrade', 'mouseover', function() { $('dl4MenuTrade').active = true; })
    Event.observe('dl4MenuTrade', 'mouseout', function() { delayedMenuRowHide('dl4MenuTrade'); })

    Event.observe('menu_truppen', 'mouseover', function() { $('dl4MenuFighting').active = true; displayMenuRow('menu_truppen', 'dl4MenuFighting'); })
    Event.observe('menu_truppen', 'mouseout', function() { delayedMenuRowHide('dl4MenuFighting'); })
    Event.observe('dl4MenuFighting', 'mouseover', function() { $('dl4MenuFighting').active = true; })
    Event.observe('dl4MenuFighting', 'mouseout', function() { delayedMenuRowHide('dl4MenuFighting'); })

    Event.observe('menu_gruppe', 'mouseover', function() { $('dl4MenuCommunity').active = true; displayMenuRow('menu_gruppe', 'dl4MenuCommunity'); })
    Event.observe('menu_gruppe', 'mouseout', function() { delayedMenuRowHide('dl4MenuCommunity'); })
    Event.observe('dl4MenuCommunity', 'mouseover', function() { $('dl4MenuCommunity').active = true; })
    Event.observe('dl4MenuCommunity', 'mouseout', function() { delayedMenuRowHide('dl4MenuCommunity'); })

    Event.observe('menu_igm', 'mouseover', function() { $('dl4MenuOther').active = true; displayMenuRow('menu_igm', 'dl4MenuOther'); })
    Event.observe('menu_igm', 'mouseout', function() { delayedMenuRowHide('dl4MenuOther'); })
    Event.observe('dl4MenuOther', 'mouseover', function() { $('dl4MenuOther').active = true; })
    Event.observe('dl4MenuOther', 'mouseout', function() { delayedMenuRowHide('dl4MenuOther'); })

    if(xPageX('dl4MainMenu') > xClientWidth() - 500) { // Falls das Menü sich rechts befindet
      reverseMainMenus();					// Müssen wir die Elemente umdrehen
    }

  }

  /**
    * Dreht die Elemente aller Hauptmenüzeilen um (für das Umschalten zwischen rechts- und linksbündigem Menü)
    */
  function reverseMainMenus() {
    var allMenus = new Array('dl4MenuBuildings', 'dl4MenuTraining', 'dl4MenuTrade', 'dl4MenuFighting', 'dl4MenuCommunity', 'dl4MenuOther'); // Liste der Menüzeilen
    for(var i = 0, len = allMenus.length; i < len; ++i) {	// Gehe alle Menüzeilen durch
      var curMenuRow = $(allMenus[i]);					// Hole aktuelle Menüzeile
      var r = $A(curMenuRow.childNodes);				// Erstelle Array aus Kindknoten
      r.reverse();							// Drehe Array um
      for(var j = 0, xlen = r.length; j < xlen; ++j) {				// Gehe alle Elemente um
        curMenuRow.appendChild(r[j]);						// Hänge die Elemente wieder an die Menüzeile
      }
    }
    menuLeft = !menuLeft;					// Setze von links auf rechtsbündig bzw. andersrum
  }

  function delayedMenuRowHide(menuElem) {
    $(menuElem).active = false;
    window.setTimeout(function() { hideIfUntouched(menuElem); }, 10);
  }

  /**
    * Stellt eine Menüzeile (showDiv) neben dem übergebenen Element (baseElem) dar
    */
  function displayMenuRow(baseElem, showDiv) {
    showDiv = $(showDiv);
    if(xPageX('dl4MainMenu') > xClientWidth() - 500) {
      xMoveTo(showDiv, xPageX(baseElem) - (showDiv.childNodes.length * 65) + (baseElem == 'menu_gruppe' ? 100 : 0), xPageY(baseElem));
    } else {
      xMoveTo(showDiv, xPageX(baseElem) + 65, xPageY(baseElem));
    }
    xShow(showDiv);
  }

  /**
    * Versteckt eine Menüzeile, wenn ???
    */
  function hideIfUntouched(menuElem) {
    menuElem = $(menuElem);
    if(!menuElem.active) {
      xHide(menuElem);
    }
  }

  /**
    * Use on element to drag another (like a windows titlebar)
    */
  function enableDragWithHelper(helperElem, moveElem, startFunc, endFunc) {
    xEnableDrag(helperElem, startFunc, new Function('ele', 'dx', 'dy', 'eveObj', 'xMoveTo(\'' + moveElem + '\', xLeft(\'' + moveElem + '\') + dx, xTop(\'' + moveElem + '\') + dy);'), endFunc);
  }

  /**
    * Sorgt im Firefox dafür, dass der Text-Cursor zu sehen ist (ein Bug verhindert dies bei Anzeige von #dl4Area im Hintergrund mit den Standard-CSS-Einstellungen)
    */
  function firefoxAreaCSSin(curEvent) {
    var dl4Area = $('dl4Area');
    xStyle('position', 'absolute', dl4Area);
    if(Scrolling.curTop == 0) Scrolling.curTop = xTop(dl4Area);
    if(Scrolling.curLeft == 0) Scrolling.curLeft = xLeft(dl4Area);
    xTop(dl4Area, xScrollTop() + Scrolling.curTop);
    xHeight(dl4Area, Math.min(Scrolling.areaHeight, -Scrolling.curTop + xClientHeight())); // Setze aktuelle Größe
    xWidth(dl4Area, Math.min(Scrolling.areaWidth, -Scrolling.curLeft + xClientWidth())); // Setze aktuelle Größe
  }
  /** Gegenstück zur obigen Funktion */
  function firefoxAreaCSSout(curEvent) {
    var dl4Area = $('dl4Area');
    xStyle('position', 'fixed', dl4Area);
    xTop(dl4Area, Scrolling.curTop);
  }


  /**
    * Bereite Gebäude und Ihre Links vor
    */
  function prepareBuildings() {

    if(((location.href.indexOf('?location=bauten') != -1 || location.href.indexOf('&location=bauten') != -1) && location.href.indexOf('decorational') == -1)|| (location.href.indexOf('location=') == -1 && location.href.indexOf('tutorial.php') == -1)) {
      Scrolling.prepare(true);			// Breite automatisch Scrolling vor, wenn wir uns in der Gebäudeansicht befinden
      //xStyle('display', 'none', 'dl4Minimizer');
      var mc = $('dl4MainContent');
      if(location.href.indexOf('location=') !== -1) xShow(mc);
      var ch = xClientHeight() 
      xStyle('bottom', '', mc);
      xHeight(mc, (ch <= 800 ? 210 : 170))
      xTop(mc, xClientHeight() - (ch <= 800 ? 230 : 190));
      if(is_ie6) {
        mc = $('dl4BuildMain');
        if(mc) {
          for(var i = 0, len = mc.childNodes.length; i < len; ++i) {
      	    xWidth(mc.childNodes[i], 280);
          }
        }
      }
    } else {
      xShow($('dl4MainContent'));
      Scrolling.prepare(false);			// Breite Basis-Scrolling vor, wenn wir uns in der Gebäudeansicht befinden
      if(location.href.indexOf('&sub=buildings') != -1) {
        if(is_ie6) {
          mc = $('dl4BuildMain');
          for(var i = 0, len = mc.childNodes.length; i < len; ++i) {
      	    xWidth(mc.childNodes[i], 280);
          }
        }
      }
    }

    var ta = $('dl4TopArea'); var cw = xClientWidth();
    if(cw > 1035) xCenter(ta); else { xWidth(ta, cw + 5); xLeft(ta, -5); $('dl4AccountInfo').setStyle({'width' : '100px'}); }// Zentriere oberen Bereich
    xShow(ta); // xShow('dl4MainContent');
    
    var dl4Area = $('dl4Area');
    if(dl4Area) {

      if(is_firefox) {				// Im Firefox Browser müssen wir in Text-Eingabe-Elementen die Styles von #dl4Area verändern, ansonsten wird durch einen Bug kein Cursor angezeigt
        var inputEles = xGetElementsByTagName('textarea'); // Hole alle Textareas
        for(var i = 0, len = inputEles.length; i < len; ++i) { // Gehe alle Textareas durch
          Event.observe(inputEles[i], 'focus', firefoxAreaCSSin);	// Ermögliche Anzeige des Textcursors beim Aktivieren des Elements
          Event.observe(inputEles[i], 'blur', firefoxAreaCSSout);	// Stelle alten Zustand wieder her bei Verlassen des Elements
        }
        var inputEles = xGetElementsByTagName('input');	// Holle alle Eingabefelder
        for(var i = 0, len = inputEles.length; i < len; ++i) {	// Gehe alle Eingabefelder durch
      	  if(inputEles[i].type == 'text') {			// Falls das Eingabefeld ein Text-Eingabefeld ist
            Event.observe(inputEles[i], 'focus', firefoxAreaCSSin);	// Ermögliche Anzeige des Textcursors beim Aktivieren des Elements
            Event.observe(inputEles[i], 'blur', firefoxAreaCSSout);		// Stelle alten Zustand wieder her bei Verlassen des Elements
          }
        }
      }

      var aH = xHeight(dl4Area);
      if(aH == 500 || aH == 504)   xHeight(dl4Area, Math.min(xClientHeight(), Scrolling.areaHeight));

      if($('dl4All').hasClassName('settleshop')) {
      	//Event.observe($('dl4SilbermineHover'), 'click', function(ev) { showPopup(this, 'dl4SilbermineH', {'left' : ev.pointerX(), 'top' : ev.pointerY() }); });
      } else {
	Event.observe($('dl4HaupthausHover'), 'click', function() { location.href='?location=truppen'; });
	Event.observe($('dl4FriedhofHover'), 'click', function() { location.href='?location=friedhof'; });
      	Event.observe($('dl4BibliothekHover'), 'click', function() { location.href='?location=bibliothek'; });
      	Event.observe($('dl4KaserneHover'), 'click', function() { location.href='?location=kaserne'; });
      	Event.observe($('dl4VerteidigungHover'), 'click', function() { location.href='?location=verteidigung'; });
      	Event.observe($('dl4SpeicherHover'), 'click', function() { location.href='?location=markt'; });
      	Event.observe($('dl4SchattenportalHover'), 'click', function() { location.href='?location=schattenportal'; });
      	Event.observe($('dl4DrachenhofHover'), 'click', function() { location.href='?location=drachenhof'; });
      	Event.observe($('dl4HexenkuecheHover'), 'click', function() { location.href='?location=hexenkueche'; });
      	Event.observe($('dl4TempelHover'), 'click', function() { location.href='?location=tempel'; });
      	Event.observe($('dl4erzmineHover'), 'click', function() { location.href='?location=ressourceinfo'; });
      	Event.observe($('dl4goldmineHover'), 'click', function() { location.href='?location=ressourceinfo'; });
      	Event.observe($('dl4saegewerkHover'), 'click', function() { location.href='?location=ressourceinfo'; });
      	Event.observe($('dl4farmHover'), 'click', function() { location.href='?location=ressourceinfo'; });
      	Event.observe($('dl4silbermineHover'), 'click', function() { location.href='?location=ressourceinfo'; });
      }
    }
  }

  function hideMainContent() {
    xHide('dl4Minimizer');
    xShow('dl4Maximizer');
    window.setTimeout(function() {
    	xStyle('display', 'none', 'dl4MainContent');
    	if($('dl4HighlightBig')) $('dl4HighlightBig').hide(); // Hide tutorial highlight if necessary
    	}, 100);
    Scrolling.prepare(true);			// Ermögliche Scrolling, wenn der Inhalt minimiert ist
  }

  function showMainContent() {
    xHide('dl4Maximizer');
    xStyle('display', 'block', 'dl4MainContent');
    xShow('dl4Minimizer');
  }

  function layerWrite(layer, text) {
    var ie = document.all;
    var dom = document.getElementById;
    if (ie || dom) {
      targetlayer = $(layer);
      if(targetlayer) targetlayer.innerHTML = text;
    }
  }

  /**
    * DOM-freundliche, inner-HTML-freie Version von layerWrite, die allerdings nur mit Text arbeitet.
    */
  function writeText(writeElem, writeText) {
    deleteContent(writeElem);
    writeElem = xGetElementById(writeElem);
    if(xDef(writeElem)) {
      writeElem.appendChild(document.createTextNode(writeText));
    }
  }

  /**
    * Funktion die eine Sekundenzahl in das Format hh:mm:ss bringt
    */
  function seconds_to_countdown(seconds, hourSep, minSep, secSep) { var oldsecs = seconds;
    if(!xDef(hourSep)) hourSep = ":";
    if(!xDef(minSep)) minSep = ":";
    if(!xDef(secSep)) secSep = "";

    var minutes = Math.floor(seconds / 60);
    seconds = seconds % 60;
    var hours = Math.floor(minutes / 60);
    minutes = minutes % 60;

    if(seconds < 10) seconds = "0" + seconds;
    if(minutes < 10) minutes = "0" + minutes;

    return (String(hours) + hourSep + String(minutes) + minSep + String(seconds) + secSep);
  }



  /**
    * php-like number_format like function, taken from: http://www.fobit.com/index.php?article=JavaScript%3A%20number_format
    */
  function number_format (number, decimals, dec_point, thousands_sep) {
    var exponent = "";
    var numberstr = number.toString ();
    var eindex = numberstr.indexOf ("e");
    if (eindex > -1)
    {
      exponent = numberstr.substring (eindex);
      number = parseFloat (numberstr.substring (0, eindex));
    }

    if (decimals != null)
    {
      var temp = Math.pow (10, decimals);
      number = Math.round (number * temp) / temp;
    }
    var sign = number < 0 ? "-" : "";
    var integer = (number > 0 ?
        Math.floor (number) : Math.abs (Math.ceil (number))).toString ();

    var fractional = number.toString ().substring (integer.length + sign.length);
    dec_point = dec_point != null ? dec_point : ".";
    fractional = decimals != null && decimals > 0 || fractional.length > 1 ?
                 (dec_point + fractional.substring (1)) : "";
    if (decimals != null && decimals > 0)
    {
      for (i = fractional.length - 1, z = decimals; i < z; ++i)
        fractional += "0";
    }

    thousands_sep = (thousands_sep != dec_point || fractional.length == 0) ?
                    thousands_sep : null;
    if (thousands_sep != null && thousands_sep != "")
    {
    for (i = integer.length - 3; i > 0; i -= 3)
        integer = integer.substring (0, i) + thousands_sep + integer.substring (i);
    }

    return sign + integer + fractional + exponent;
  }


  function open_bl(linktext) {
    var fenster = window.open("./buddylist.php" + linktext, "Buddylist","scrollbars,width=250,height=300,left=200,top=200,resizable=yes");
    fenster.focus();
    return(false);
  }

  function profil(profil_id) {
    opener.location.href = 'main.php?location=profil&uid=' + profil_id.replace(".", "%2E").replace("/", "%2F");
    opener.focus();
    return(false);
  }
  
  /**
   * Calculate the time (in seconds) that is necessary to produce a given amount of resources, based on starting values and production amounts.
   * Prints the resulting time and resulting resource stocks into the respective fields
   */
  function calcProdTime(erzStart, goldStart, holzStart, nahrungStart, silberStart, erzProd, goldProd, holzProd, nahrungProd, silberProd, erzTarget, goldTarget, holzTarget, nahrungTarget, silberTarget) {
    // The following vars correspond to productions steps (10 minutes, 600 seconds)
    var timeToProdErz = (erzProd == 0 ? 0 : Math.ceil(Math.max(0, (isNaN(erzTarget) ? 0 : erzTarget) - erzStart) / erzProd)); 
    var timeToProdGold = (goldProd == 0 ? 0 : Math.ceil(Math.max(0, (isNaN(goldTarget) ? 0 : goldTarget) - goldStart) / goldProd)); 
    var timeToProdHolz = (holzProd == 0 ? 0 : Math.ceil(Math.max(0, (isNaN(holzTarget) ? 0 : holzTarget) - holzStart) / holzProd)); 
    var timeToProdNahrung = (nahrungProd == 0 ? 0 : Math.ceil(Math.max(0, (isNaN(nahrungTarget) ? 0 : nahrungTarget) - nahrungStart) / nahrungProd)); 
    var timeToProdSilber = (silberProd == 0 ? 0 : Math.ceil(Math.max(0, (isNaN(silberTarget) ? 0 : silberTarget) - silberStart) / silberProd));
    var maxProdTime = Math.max(Math.max(Math.max(Math.max(timeToProdNahrung, timeToProdErz), timeToProdGold), timeToProdHolz), timeToProdSilber);
    
    layerWrite('prodcalc_result_time', I18N.durationFormat(maxProdTime * 600, true));
    layerWrite('prodcalc_result_erz', I18N.numberFormat(erzStart + maxProdTime * erzProd) + ' (+' + I18N.numberFormat(maxProdTime * erzProd) + ')');
    layerWrite('prodcalc_result_gold', I18N.numberFormat(goldStart + maxProdTime * goldProd) + ' (+' + I18N.numberFormat(maxProdTime * goldProd) + ')');
    layerWrite('prodcalc_result_holz', I18N.numberFormat(holzStart + maxProdTime * holzProd) + ' (+' + I18N.numberFormat(maxProdTime * holzProd) + ')');
    layerWrite('prodcalc_result_nahrung', I18N.numberFormat(nahrungStart + maxProdTime * nahrungProd) + ' (+' + I18N.numberFormat(maxProdTime * nahrungProd) + ')');
    layerWrite('prodcalc_result_silber', I18N.numberFormat(silberStart + maxProdTime * silberProd) + ' (+' + I18N.numberFormat(maxProdTime * silberProd) + ')');
  }

  /**
   * Calculate the amount that is producd in a given time, based on starting values and production amounts.
   * Prints the resulting resulting resource stocks into the respective fields
   */
  function calcProdAmount(erzStart, goldStart, holzStart, nahrungStart, silberStart, erzProd, goldProd, holzProd, nahrungProd, silberProd, timeTarget) {
    timeTarget = Math.floor(isNaN(timeTarget) ? 0 : timeTarget * 6);
    layerWrite('prodcalc_result_erz', I18N.numberFormat(erzStart + timeTarget * erzProd) + ' (+' + I18N.numberFormat(timeTarget * erzProd) + ')');
    layerWrite('prodcalc_result_gold', I18N.numberFormat(goldStart + timeTarget * goldProd) + ' (+' + I18N.numberFormat(timeTarget * goldProd) + ')');
    layerWrite('prodcalc_result_holz', I18N.numberFormat(holzStart + timeTarget * holzProd) + ' (+' + I18N.numberFormat(timeTarget * holzProd) + ')');
    layerWrite('prodcalc_result_nahrung', I18N.numberFormat(nahrungStart + timeTarget * nahrungProd) + ' (+' + I18N.numberFormat(timeTarget * nahrungProd) + ')');
    layerWrite('prodcalc_result_silber', I18N.numberFormat(silberStart + timeTarget * silberProd) + ' (+' + I18N.numberFormat(timeTarget * silberProd) + ')');
  }

  function spellbook(spell, showActions) {

    if(XHR1.status != XHR1.NOXMLOBJ) {				// Falls asynchrone Requests erlaubt werden
      var newSpellbookNode = $('dl4Spellbook');
      if(!newSpellbookNode) {						// Falls das Spellbook noch nicht angezeigt wird
        var mainObject = xGetElementById(mainObjectId);					// Hole DL4-Content
        var newSpellbookNode = document.createElement("div");			// Erstelle Spellbook-DIV
        newSpellbookNode.id = 'dl4Spellbook';					// Setze ID für Spellbook

        var newSpellbookMoverNode = document.createElement("div");			// Erstelle Spellbook-Dragbar-DIV
        newSpellbookMoverNode.id = 'dl4SpellbookMover';				// Setze ID für Spellbook-Dragbar
        newSpellbookNode.appendChild(newSpellbookMoverNode);			// Füge Spellbook-Dragbar hinzu

        newSpellbookNode.appendChild(makeAbortButton('dl4Spellbook', 'dl4SpellbookClose')); // Erstelle Schließ-Button

        var newSpellbookContentNode = document.createElement("div");		// Erstelle Spellbook-Inhalt-DIV
        newSpellbookContentNode.id = 'dl4SpellbookContent';			// Setze ID für Spellbook-Inhalt
        newSpellbookNode.appendChild(newSpellbookContentNode);			// Füge Spellbook-Inhalt hinzu

        mainObject.appendChild(newSpellbookNode);				// Füge Spellbook hinzu

        xMoveTo(newSpellbookNode, 200, xScrollTop() + 200);
        enableDragWithHelper('dl4SpellbookMover', 'dl4Spellbook', null, null);
      }

      if(XHR1.busy) {							// Falls das Request-Objekt noch arbeitet
        setTimeout('spellbook(' + spell + ')', 250);				// Starten wir diese Funktion in 250ms erneut
      } else {
      	var curDate = new Date();
        if(XHR1.send('GET', 'spellbook.php', 'spell=' + spell + '&showaction=' + (showActions ? 'true' : 'false') + '&curtime=' + curDate.getTime(), 15000, false, false, false, spellbookRequest)) {
          return(false);
        }
        xHide(newSpellbookNode);
      }
    }
    /* Fallback, falls XMLHTTP-Requests nicht klappen: Popup-Fenster */
    var fenster = window.open('spellbook.php?html=yes&spell=' + spell, 'Spellbook', 'scrollbars,width=370,height=470,left=200,top=200,resizable=yes');
    fenster.focus();

    return(false);
  }

  function changeUnit(unitDivId) {
    if(typeof(curUnitDiv) == 'undefined') {
      xStyle('display', 'none', 'unitdiv1');
    } else {
      xStyle('display', 'none', 'unitdiv' + curUnitDiv);
    }
    curUnitDiv = unitDivId;
    xStyle('display', 'block', 'unitdiv' + curUnitDiv);
  }


  /**
    * Funktion die einen HTTP-Request empfängt und die entsprechenden Daten in den Spellbook-Bereich schreibt
    */
  function spellbookRequest(httpReq, reqStatus, reqData) {
    if (reqStatus == XHR1.OK) {					// Wenn der Status der HTTP-Antwort OK ist
      spellbookElem = xGetElementById('dl4Spellbook');			// Hole das Spellbook
      if(spellbookElem) {						// Falls das Spellbook gefunden wurde
      	xShow('dl4Spellbook');							// Zeige Spellbook
      	spellbookElem.lastChild.innerHTML = httpReq.responseText;				// Schreibe den Text aus der HTTP-Antwort in das DIV
      }
    } else {
      s = '';
      if (reqStatus & XHR1.TIMEOUT) {
        s = '<p>Timeout Error<\/p>';
      }
      if (reqStatus & XHR1.NOXMLCT) {
        s = '<p>XML content-type expected but received: ' + req.getResponseHeader('Content-Type') + '<\/p>';
      }
      if (reqStatus & XHR1.RSPERR) {
        s = '<p>Response Error (' + httpReq.status + '): ' + httpReq.statusText + '<\/p>';
      }
      xGetElementById('dl4Spellbook').innerHTML = s;
    }

  }


  function areaMapWriter(stepsizex, stepsizey, mapsizex, mapsizey, pixelsizex, pixelsizey, theoffsetX, theoffsetY) {
    for(y = 0; y < stepsizey; y++) {
      for(x = 0; x < stepsizex; x++) {
        document.write('<area shape=\"rect\" coords=\"' + Math.round(x * pixelsizex / stepsizex) + ',' + Math.round(y * pixelsizey / stepsizey) + ',' + Math.round(((x + 1) * pixelsizex / stepsizex) - 1) + ',' + Math.round(((y + 1)* pixelsizey / stepsizey) - 1) + '\" href=\"?location=karte&amp;x=' + (theoffsetX + Math.round((x * mapsizex / stepsizex) + (mapsizex / (stepsizex * 2)))) + '&amp;y=' + (theoffsetY + Math.round((y * mapsizey / stepsizey) + (mapsizey / (stepsizey * 2)))) + '&amp;dot=yes\" />\n');
      }
    }
  }

  /**
    * Abladen-Funktion mit vorherigen Frage
    */
  function unloadAction(questionText, unloadType) {
    var actionString;
    if(unloadType == 1) actionString = "disableFormElement('loadform', 'unload', 'Abladen'); document.forms['loadform'].elements['loadaction'].value = 'unload'; document.forms['loadform'].submit();";
    else if(unloadType == 2) actionString = "disableFormElement('loadform', 'unload_all', 'Alles abladen'); document.forms['loadform'].elements['loadaction'].value = 'unload_all'; document.forms['loadform'].submit();";
    if(questionText == false) {
      eval(actionString);
    } else {
      questionAndAction(questionText, actionString);
    }
    return(false);
    
      
  }


  /**
    * Simple go back function to place inside a hyperlink.
    */
  function dlGoBack() {
    history.back();
    return(false);
  }

  var monsterTypeIcons = new Array(); monsterTypeIcons[0] = 'schwert'; monsterTypeIcons[1] = 'schwert2'; monsterTypeIcons[2] = 'distanz'; monsterTypeIcons[3] = 'magie'; monsterTypeIcons[4] = 'magie2'; monsterTypeIcons[10] = 'pfeil_gruen_hoch';

  function qInfo(xCoord, yCoord, uName, sName, cName, areaId, entfernung, isAttackable, zeit, mdef, monster) {
    layerWrite('koord', xCoord + ':' + yCoord);
    layerWrite('user', uName);
    layerWrite('sname', sName);
    layerWrite('area', I18N.wordTable['AREANAME_' + String(areaId)]);
    cName = cName.replace("<", "&lt;");
    cName = cName.replace(">", "&gt;");
    layerWrite('clan', cName + '&nbsp;');
    layerWrite('entf', entfernung + ' Km');
    if(isAttackable) {
      noobText = "<span style=\'color: greenyellow; font-weight: bold;\'>" + I18N.getSpecificString('YES') + "</span>";
    } else {
      noobText = "<span style=\'color: tomato; font-weight: bold;\'>" + I18N.getSpecificString('NO') + "</span>";
    }
    layerWrite('noob', noobText);
    layerWrite('zeit', zeit);
    if(monster != 0) {
      monstertext = '<table style="width: 190px; margin-top: 5px;"><tr><td colspan="3" style="text-align: left; font-weight: bold; padding-bottom: 5px;">' + I18N.getSpecificString('MONSTERFIELD_TYPE_' + String(monster[0] % 10)) + (monster[0] >= 10 ? ' ' + I18N.getSpecificString('MONSTERFIELD_CHALLENGE') : '') + '</td></tr>';
      var rows = 0;
      for(var i = 1, len = monster.length; i < len; i += 3) {
        monstertext += '<tr>';
        if(i == 1) {
          monstertext += '<td rowspan="' + ((len - 1) / 3) + '" style="width: 40px; text-align: left; vertical-align: top;"><img src="' + useGrafikpfad + '/icons/36x36/' + monsterTypeIcons[monster[0] % 10] + '.gif" alt="" />';
          if(monster[0] >= 10) monstertext += ' <img src="' + useGrafikpfad + '/icons/36x36/' + monsterTypeIcons[10] + '.gif" alt="" />';
          monstertext += '</td>';
        }
        monstertext += '<td class="tier' + String(monster[i + 2]) + '" style="text-align: left;">' + (monster[i + 2] > 0 ? '<img src="' + useGrafikpfad + '/icons/12x12/tier' + String(monster[i + 2]) + '.gif" alt="" /> ' : '') + monster[i] + ':</td><td style="text-align: left; width: 20px;">' + monster[i + 1] + '</td></tr>';
        rows++;
      }
      while(rows++ < 5) monstertext += '<tr><td colspan="2">&nbsp;</td></tr>';
      monstertext += '</table>';
    } else {
      if(mdef == 0) {
        monstertext = '<strong>' + I18N.getSpecificString('JS_NO_MONSTERS_ON_FIELD') + '</strong>';
      } else {
        monstertext = '<strong>' + I18N.getSpecificString('JS_MONSTER_DISPLAY_DEACTIVATED') + '</strong>';
      }
    }
    layerWrite('monster', monstertext);
  }
  
  /**
    * Hole die Endzeit-Variablen aus der Queue
    */
  function getEndzeit() {
    endzeit = new Array();
    var qTbl = $('qTbl');
    if(!qTbl) return(false);
    var queueRows = qTbl.getElementsByTagName('TR');
    for(var i = 0, len = queueRows.length; i < len; ++i) {
      if(queueRows[i].id && queueRows[i].id.indexOf('q') == 0) {
      	endzeit[queueRows[i].lastChild.firstChild.id.substr(4)] = queueRows[i].id.substr(queueRows[i].id.indexOf('_') + 1);
      }
    }
    return(true);
  }

  function dl4Queue() {
    secondssincetick++;
    xWidth($('dl4ResBar').firstChild, Math.min(120, Math.floor(secondssincetick / 600 * 120)));
    var curTime = new Date(servertime * 1000);
    servertime++;
    var dltime = $('dl4Time');
    dltime.firstChild.data = (curTime.getHours() < 10 ? '0' : '') + curTime.getHours() + ':' + (curTime.getMinutes() < 10 ? '0' : '') + curTime.getMinutes() + ':' + (curTime.getSeconds() < 10 ? '0' : '') + curTime.getSeconds();
    if(endzeit == undefined) getEndzeit();
    for(var i = 0, len = endzeit.length; i < len; i++) {
      if(endzeit[i] > 0) {
        endzeit[i]--;
        sek = endzeit[i];
        min = 0;
        std = 0;
        min = Math.floor(sek / 60);
        sek = sek % 60;
        std = Math.floor(min / 60);
        min = min % 60;
        if(sek < 10) sek = '0' + sek;
        if(min < 10) min = '0' + min;
        tstring = std + ':' + min + ':' + sek;
        layerWrite('feld' + i, tstring);
      } else {
        layerWrite('feld' + i, I18N.getSpecificString('QUEUE_ENTRY_READY'));
      }
    }
  }

  function mark(formname, status, elemName) {
    for(var i = 0, len = document.forms[formname].length; i < len; i++) {
      if(!xDef(elemName) || elemName == document.forms[formname].elements[i].name) document.forms[formname].elements[i].checked = status;
    }
  }

  function check_fieldsize(formname, fieldname, statusfield, nmaxl) {
    zeichen = document.forms[formname].elements[fieldname].value;

    if(zeichen.length > nmaxl) layerWrite(statusfield, "\<span style='color: tomato;'\>" + zeichen.length + " / " + nmaxl + " Zeichen\<\/span\>");
    else layerWrite(statusfield, zeichen.length + " / " + nmaxl + " Zeichen");
  }

  function markType(formname, typename, elemName) {
    for(var i = 0, len = document.forms[formname].elements.length; i < len; i++) {
      if(document.forms[formname].elements[i].id.indexOf(typename) != -1 && (!xDef(elemName) || elemName == document.forms[formname].elements[i].name)) {
      	if(document.forms[formname].elements[i].checked == true) document.forms[formname].elements[i].checked = false; else document.forms[formname].elements[i].checked = true;
      }
    }
  }
  
  /**
    * Zeigt ein Fenster an, in dem die Kosten eines Gegenstandes gezeigt werden, ohne Link zum Marktplatz
    */
  function kostenItem(item, erz, gold, holz, nahrung, silber, kraft, op, veggie) {

    var itemInfos = new Array(10);				// Create new array for the creation of specific strings
    itemInfos[0] = item;
    itemInfos[1] = I18N.numberFormat(kraft, 0);
    itemInfos[2] = I18N.numberFormat(op, 0);
    itemInfos[3] = useGrafikpfad;
    itemInfos[4] = I18N.numberFormat(erz, 0);
    itemInfos[5] = I18N.numberFormat(gold, 0);
    itemInfos[6] = I18N.numberFormat(holz, 0);
    itemInfos[7] = veggie;
    itemInfos[8] = I18N.numberFormat(nahrung, 0);
    itemInfos[9] = I18N.numberFormat(silber, 0);

    infoWindow(I18N.getSpecificString('ITEM_COSTS_POPUP', itemInfos), 'kostenItem');
    xMoveTo('kostenItem', 200, xScrollTop() + 300);
    return(false);
  }

  function centerMapOn(xcoord, ycoord, linkLoc) {
    location.href = '?location=' + linkLoc + '&x=' + xcoord + '&y=' + ycoord;
  }

  function changeStats(fromday, frommonth, fromyear, today, tomonth, toyear) {
    document.forms["statistics"].elements["von_tag"].selectedIndex = fromday - 1;
    document.forms["statistics"].elements["von_monat"].selectedIndex = frommonth - 1;
    document.forms["statistics"].elements["von_jahr"].selectedIndex = fromyear - 2005;
    document.forms["statistics"].elements["bis_tag"].selectedIndex = today - 1;
    document.forms["statistics"].elements["bis_monat"].selectedIndex = tomonth - 1;
    document.forms["statistics"].elements["bis_jahr"].selectedIndex = toyear - 2005;
  }

  /* Tooltips - ganz einfach. Genommen von: http://www.webmatze.de/webdesign/javascript/tooltips.htm */
  var wmtt = null;

  /* Dieser Teil ist nur wichtig, wenn wir die Tooltips zur Laufzeit bewegen wollen. Sollte also eher in der Datei selbst als JS gesetzt werden
     Zur Laufzeit bewegen ist auch deswegen Problematisch, weil absolut positionierte DIVs als Elternelement genommen werden und damit die Positionierung schwer wird

  document.onmousemove = updateWMTT;

  function updateWMTT(e) {
    x = (document.all) ? window.event.x + document.body.scrollLeft : e.pageX;
    y = (document.all) ? window.event.y + document.body.scrollTop  : e.pageY;

    if (wmtt != null) {
      wmtt.style.left = (x + 20) + "px";
      wmtt.style.top = (y + 20) + "px";
    }
  }*/

  function showWMTT(id, x, y) {
    wmtt = document.getElementById(id);
    if(wmtt != null) {
      wmtt.style.display = "block";
      wmtt.style.left = (x + 20) + "px";
      wmtt.style.top = (y + 20) + "px";
    }
  }

  function hideWMTT() {
    wmtt.style.display = "none";
  }

  /**
   * Verändere die aktuelle Zutat entsprechend der gewählten und wähle die nächste Zutat
   * Übergeben werden der Name der neuen Zutat für das Formular, die URL des leeren Bildes (wichtig für das Zutatenwechseln),
   * die URL des Zutatenicons selbst, so wie die URL des Pfeiles der für die neue aktuelle Zutat gesetzt werden muss
   */
  function hexenkuecheIngredientChange(ingredientCount, newIngredient, emptyUrl, iconUrl, arrowUrl) {
    document.forms['brauen'].elements['ingredient' + String(currentIngredient)].value = newIngredient; // Setze das Formularfeld der aktuellen Zutat auf die neue Zutat

    var iconobj = xGetElementById('ingredient' + String(currentIngredient) + 'icon');				// Hole das Bild für diese Zutat

    if(!iconobj) return(false);								// Falls das Bild nicht geholt werden konnt gehen zurück

    var cursrc = new String(iconobj.src);							// Erstelle Stringobjekt zum durchsuchen
    if(cursrc.search(iconUrl.substring(iconUrl.lastIndexOf('/') + 1, iconUrl.length - 4)) == -1) iconobj.src = iconUrl; // Falls das Icon nicht bereits gesetzt ist, setze es. (Das If ist nur nötig weil der IE6 zu dumm zum scheissen ist und da Probleme macht -.-)

    if(currentIngredient == ingredientCount) changeCurrentIngredient(1, emptyUrl, arrowUrl);
    else changeCurrentIngredient(currentIngredient + 1, emptyUrl, arrowUrl);
  }

  /**
   * Verändere den Pfeil auf die aktuelle Zutat und lösche den alten Pfeil
   * Übergeben werden die Nummer der neuen Zutat, die URL des leeren Bildes, so wie die URL des
   * Pfeiles der für die neue aktuelle Zutat gesetzt werden muss
   */
  function changeCurrentIngredient(newIngredient, emptyUrl, iconUrl) {

    var selobj = xGetElementById('ingredient' + String(currentIngredient) + 'sel');	// Hole das Bild für den Zeiger auf die aktuelle Zutat.
    if(!selobj) return(false);								// Falls nicht gefnuden, springe zurück
    selobj.src = emptyUrl;								// Ansonsten ersetze das Bild durch das leere Bild

    currentIngredient = newIngredient;							// Setze die neue Zutat

    selobj = xGetElementById('ingredient' + String(currentIngredient) + 'sel');		// Hole das Bild für den Zeiger auf die neue Zutat
    if(!selobj) return(false);								// Falls nicht gefnuden, springe zurück
    selobj.src = iconUrl;								// Setze das Pfeilbild für die neue Zutat

  }

  /**
    * Funktion die ein bestimmtes Element deaktiviert in einem Formular
    * Meist werden hiermit Submit Buttons deaktiviert, damit sie nicht aus versehen doppelt geklickt werden.
    */
  function disableFormElement(formname, elemname, newtext) {
    document.forms[formname].elements[elemname].disabled = 1;
    if(newtext != '') document.forms[formname].elements[elemname].value = newtext;
  }

  /**
    * Funktion die ein bestimmtes Element deaktiviert
    * Meist werden hiermit Submit Buttons deaktiviert, damit sie nicht aus versehen doppelt geklickt werden.
    */
  function disableElement(elemId, newtext) {
    elem = xGetElementById(elemId);
    if(elem) {
      elem.disabled = 1;
      if(newtext != '') elem.value = newtext;
    }
  }


  /**
    * Funktion die im IGM-Menü das Formular absendet, sofern ein Menüpunkt gewählt wurde, der nicht die
    * Auswahl eines Ordners erfordert.
    */
  function submitIGMForm(controlMenuAddition, currentFolderId) {
    selectedOption = document.forms['igm_list'].elements['perform' + controlMenuAddition].options[document.forms['igm_list'].elements['perform' + controlMenuAddition].selectedIndex].value; // Hole den aktuellen Wert des Perform-Select-Menüs
    if(selectedOption == "private" || selectedOption == "public" || selectedOption == "deletefolder") {
      document.forms['igm_list'].elements['folderid' + controlMenuAddition].selectedIndex = currentFolderId; // Setze den aktuell offenen Ordner als zu bearbeitenden Ordner
      document.forms['igm_list'].submit();				// Schicke das Formular ab
    } else if(selectedOption == 'filter') {
      $('igfilt').appear({ duration: 0.5 });
    } else if(selectedOption != "moveto") { // Falls es nicht "bewege nach", "für Sitter sichtbar machen" oder "für Sitter unsichtbar machen" ist
      document.forms['igm_list'].submit();				// Schicke das Formular ab
    }
  }

  function calc_market(mode, erz, holz, nahrung, silber, sirriline) {
    var Gewinn = 0;
    var Kosten = 0;
    
    var sirriSplit = sirriline.split(",");
    var sirriValues = new Array();
    for(var i = 0, len = sirriSplit.length; i < len; ++i) {
    	var curSplit = sirriSplit[i].split(":");
    	sirriValues[parseInt(curSplit[0], 10)] = parseInt(curSplit[1], 10);
    }
    
    Gewinn += document.forms["markt"].elements["sell_erz"].value.replace("k", "000") * erz;
    Kosten += document.forms["markt"].elements["buy_erz"].value.replace("k", "000") * erz;

    Gewinn += document.forms["markt"].elements["sell_holz"].value.replace("k", "000") * holz;
    Kosten += document.forms["markt"].elements["buy_holz"].value.replace("k", "000") * holz;

    Gewinn += document.forms["markt"].elements["sell_nahrung"].value.replace("k", "000") * nahrung;
    Kosten += document.forms["markt"].elements["buy_nahrung"].value.replace("k", "000") * nahrung;

    Gewinn += document.forms["markt"].elements["sell_silber"].value.replace("k", "000") * silber;
    Kosten += document.forms["markt"].elements["buy_silber"].value.replace("k", "000") * silber;

    Gewinn += sirriValues[parseInt(document.forms["markt"].elements["sell_sirriline"].options[document.forms["markt"].elements["sell_sirriline"].selectedIndex].value, 10)];

    if(mode == "buy") layerWrite("kosten", I18N.numberFormat(Math.ceil(Kosten), 0) + " Gold");
    else layerWrite("gewinn", I18N.numberFormat(Math.floor(Gewinn), 0) + " Gold");
  }

  /**
   * Funktion um die Werte aus wollows Resrechner zu parsen
   * written by urbus
   */
  function doParsePayback () {

    // reset all fields here!

    var myPayback = document.forms['judgehim'].elements['ignorearea'].value;
    var myPaybackArray = myPayback.split("\n", 10);
    var myPaybackErrorString = "";

    for (var i = 0; i < myPaybackArray.length; ++i) {
      if (myPaybackArray[i].charAt(0).match(/\d/)) {
        var myCurrentPayback = myPaybackArray[i].toLowerCase();
        myCurrentPayback = myCurrentPayback.replace(/[^a-z0-9]/g,"");

        var myPaybackIndex = myCurrentPayback.search(/[^\d\.]/);
        var myPaybackAmount = myCurrentPayback.substring(0, myPaybackIndex);
        var mayPaybackType = myCurrentPayback.substring(myPaybackIndex);

        if (document.forms['judgehim'].elements['debt_'+mayPaybackType]) {
          document.forms['judgehim'].elements['debt_'+mayPaybackType].value = myPaybackAmount;
        } else {
          myPaybackErrorString += "Fehler, " + mayPaybackType + " ist kein gültiger Typ, bitte Eingabe überprüfen. \n";
        }
      }
    }

    if (myPaybackErrorString)
      alert(myPaybackErrorString);

  }

  function showNotes(e) {
    var notes = $('dl4Notepad');			// Hole Notizblock
    if(!notes) {					// Falls Notizblock nicht vorhanden
      reloadNotes = true;
      mainObject = xGetElementById(mainObjectId);			// Hole DL4-Content
      notes = document.createElement("div");			// Erstelle Notizblock-DIV
      notes.id = 'dl4Notepad';					// Setze ID für Notizblock
      
      var newNotesCloseNode = makeAbortButton(function() { xStyle('display', 'none', 'dl4Notepad'); }, 'dl4NotepadClose'); // Erstelle Close-Button
      notes.appendChild(newNotesCloseNode);			// Füge Close Button hinzu
      var noteContentNode = document.createElement("div");	// Erstelle Inhaltsknoten
      notes.appendChild(noteContentNode);			// Füge Inhaltsknoten hinzu

      mainObject.appendChild(notes);				// Füge Notizblock hinzu
    }

    if(reloadNotes == true) {

        if(!XHR1.busy) {							// Falls das Request-Objekt noch arbeitet
      	  var curDate = new Date();

      	  var repAF = new Object();
          repAF.fCall = outputNotes;
          repAF.noteContent = notes.lastChild;
          XHR1.send('GET', 'actions.php', 'location=notes&curtime=' + curDate.getTime(), 15000, false, true, repAF, processRequest);
        }     
    }
    if(xGetComputedStyle(notes, 'display') == 'none') {	// Falls der Block noch nicht angezeigt wurde
      xStyle('zIndex', '10105', notes);				// Nicht zu hoch ansetzen - warum auch immer der z-Index gelöscht wird aus dl4.css -.-
      xStyle('display', 'block', notes);			// Zeige Notizblock an
      xCenter(notes);
    } else {						// Falls der Notizblock bishre angezeigt wurde
      xStyle('display', 'none', notes);				// Vertsecke ihn nun
    }
    return(false);
  }
  
  function outputNotes(responseData) {
    $('dl4Notepad').lastChild.innerHTML = responseData[0].message;
    enableDragWithHelper('dl4NoteMover', 'dl4Notepad', null, null); // Ermögliche das Ziehen des Statusfensters
    reloadNotes = false;
  }

  function editNotes() {
    deleteNodeById('dl4Notepad');
    firefoxAreaCSSin();
    reloadNotes = true;
    xStyle('display', 'block', 'dl4Notes');
    if(!notesShown) {
      layerWrite('dl4Notes', '<iframe src="notes.php" id="dl4NoteFrame" name="dl4NoteFrame" style="width: 500px; height: 475px; margin: 25px auto 0px auto; border: 0px;" scrolling="auto" marginheight="0" marginwidth="0" frameborder="0"></iframe><br /><div style="width: 100%; text-align: center;"><input type="button" name="submitnotes" id="submitnotes" value="' + I18N.getSpecificString('SAVE_NOTES') + '" class="button" onclick="saveNotes();" /><input type="button" name="closenotes" id="closenotes" value="' + I18N.getSpecificString('CLOSE_NOTES') + '" class="button" onclick="closeNotes();" style="margin-left: 25px;" /></div>');
      xMoveTo('dl4Notes', 200, 10);
      notesShown = true;
    } else {
      window.frames['dl4NoteFrame'].location.href = 'notes.php';
    }
    return(false);
  }

  function saveNotes() {
    if(window.frames['dl4NoteFrame'].document.forms['notizblock']) {
      window.frames['dl4NoteFrame'].document.forms['notizblock'].submit();
    }
    reloadNotes = true;
    closeNotes();
  }

  function closeNotes() {
    //layerWrite('dl4Notes', '');
    firefoxAreaCSSout();
    xStyle('display', 'none', 'dl4Notes');
  }
  
  /**
    * Kaufe ein Söldnerpack
    */
  function buyPack(packName, packId) {
    var packNames = new Array(1);				// Create new array for the creation of specific strings
    packNames[0] = packName;				// Add the pack name as first and only element of the array
    createQuestionWindow({	message: I18N.getSpecificString('HIRE_PACK_QUESTION', packNames) + "\n",
					performAction: function() { document.forms['packid_' + packId].submit(); }
					});
    return(false);
  }
  
  /**
    * Setzt alle bis auf den gewählten Einheitentyp bei Söldner auf "normal" zurück
    */
  function resetOthers(currentForm, currentSelect, packId, cost) {
    var selectCosts = new Array(0, 5, 12, 24, 40);
    var tierClass = String(currentForm.elements['changeu_' + currentSelect].options[currentForm.elements['changeu_' + currentSelect].selectedIndex].className);
    var tierLevel = parseInt(tierClass.charAt(tierClass.length - 1));;
    $('packcost_' + packId + '_wappen').innerHTML = (String) (cost + selectCosts[tierLevel]);
    for(var i = 0, len = currentForm.length; i < len; i++) {
      if(currentForm.elements[i].name.indexOf('changeu') != -1 && currentForm.elements[i].name.indexOf('_' + currentSelect) == -1) currentForm.elements[i].selectedIndex = 0;
    }
  }

  function questionAndRelocation(question, relocation, abort) {
    qARAction = {
        				message: question + '\n',
        				performAction: function() { location.href = relocation.replace(/~/g, '&'); }
        				}; // Create action description
    if(typeof(abort) != 'undefined') qARAction.abortAction = function() { location.href = abort.replace(/~/g, '&'); }; // Add an abort action if provided
    createQuestionWindow(qARAction);	// Create question window
    return(false);
  }
  
  function questionAndAction(question, performAct) {
    createQuestionWindow({
        				message: question + '\n',
        				performAction: function() { eval(performAct); }
        				});
    return(false);
  }

  function questionAndRelocation2(question, relocation) {
    if(confirm(question)) {
      location.href = relocation.replace(/~/g, "&");
      return(false);
    }
    return(false);
  }

  function justRelocation(relocation) {
    location.href = decodeJsLink(relocation);
    return(false);
  }

  function openWindow(relocation) {
    window.open(decodeJsLink(relocation), makeSimpleHash(relocation) + String(Math.floor(Math.random() * 1000)), 'width=800,height=600,left=0,top=100,toolbar=yes,location=yes,directories=yes,status=yes,menubar=yes,scrollbars=yes,copyhistory=yes,resizable=yes');
    return(false);
  }
  
  function makeSimpleHash(theString) {
    var theHash = 0;
    for(var i = 0, len = theString.length; i < len; ++i) {
      theHash = ((37 * theHash) + theString.charCodeAt(i)) & 0xff;
    }
    return('theHash' + String(theHash));
  }

  
  /**
    * Dekodiert Links die z.B. für JS verwendet werden um Sonderzeichen wie # und & zu kodieren
    */
  function decodeJsLink(linkString) {
    return(linkString.replace(/~~/g, "#").replace(/~/g, "&").replace(/&amp;/g, "&"));
  }

  function justRelocationOpener(relocation) {
    opener.location.href = relocation.replace(/~/g, "&").replace(/&amp;/g, "&");
    opener.focus()
    return(false);
  }


  function show_upload_upic(addition) {
    var fenster = window.open("./upload_pic.php" + addition, "Upload", "scrollbars,width=300,height=400,left=200,top=200");
    fenster.focus();
  }

  function show_upload_gpic() {
    var fenster = window.open("./upload_grouppic.php", "Upload", "scrollbars,width=350,height=475,left=200,top=200");
    fenster.focus();
  }

  function show_upload_gpic_small() {
    var fenster = window.open("./upload_grouppic.php?smallpic=yes", "Upload", "scrollbars,width=350,height=475,left=200,top=200");
    fenster.focus();
  }


  function askForRecipientAndForward(igmID) {
    var sendTo = window.prompt("An wen soll die IGM im Original weitergeleitet werden?");
    if(sendTo != null) {
      location.href= "?location=igm&sub=lesen&igm=" + igmID + "&action=yes&send_original=" + sendTo;
    }
  }

  function checkGroupType(selectObj) {
    groupType = selectObj.options[selectObj.selectedIndex].value;
    if(groupType == 10) return(confirm(I18N.getSpecificString('GTYPE_ANARCHIE_BONUS')));
    else if(groupType == 12) return(confirm(I18N.getSpecificString('GTYPE_SCHATTENBRUT_BONUS')));
    else if(groupType == 13) return(confirm(I18N.getSpecificString('GTYPE_RITUALISTEN_BONUS')));
    else if(groupType == 14) return(confirm(I18N.getSpecificString('GTYPE_JAEGER_SAMMLER_BONUS')));
    else return(true);
  }

  // Grandioses JavaScript von urbus, das die Einheiten bei Doppelklick auf eine Checkbox in die entsprechende Reihe schickt
  function shiftTypeBack(inName, inTarget) {
    var myObjects = document.getElementsByTagName('TR');
    for(var i = 0, len = myObjects.length; i < len; i++) {
      var myObject = myObjects[i];
      if (myObject.id.indexOf(inName) == 0) {
        myInnerObjects = myObject.getElementsByTagName('INPUT');
        myInnerObjects[inTarget].click();
      }
    }
  }


  function markForm(formname, listname, liststatus) {
    for (i = 0; i < document.forms[formname].length; i++)
    {
      if(document.forms[formname].elements[i].name == listname)
        document.forms[formname].elements[i].checked = liststatus;
    }
  }

  /**
    * Diese Funktion hilft, die erste Checkbox in einem bestimmten HTML-Element (meist Tabellenzeile / TR)
    * zu markieren anhand des wertes des dritten INPUT Elements innerhalb des HTML-Elements
    */
  function markTypeByHTMLElement(elemname, elemid) {
    var myObjects = document.getElementsByTagName(elemname);	// Hole alle Elemente vom gewünschten Typ
    for (i = 0; i < myObjects.length; i++) {			// Gehe alle Elemente durch
      var myObject = myObjects[i];					// Hole das Element
      myInnerObjects = myObject.getElementsByTagName('INPUT');		// Hole alle INPUT-Elemente die innerhalb dieses HTML-Elements sind
      if(myInnerObjects.length < 2) continue;				// Falls die Tabellenzeile nicht mindestens 2 INPUT-Elemente hat (1. Checkbox zum anwählen, 2. (Hidden) ID, weitere optional)
      if (myInnerObjects[1].value == elemid) {					// Falls die ID des Elements mit der gesuchten übereinstimmt
        if(myInnerObjects[0].checked) {						// Falls das erste Element markiert ist (sollte Checkbox sein)
          myInnerObjects[0].checked = false; 						// Deselektiere es
        } else {								// Falls das erste Element nicht markiert ist
          myInnerObjects[0].checked = true;						// Selektiere es
        }
      }
    }
  }

  /**
    * Funktion zum Berechnen der Heilkosten aller aktiv ausgewählten
    * Einheiten im Heilungsmenü
    */
  function calcHealingCost(resAvailable, whichRes, loc, healWith, veggie, backTo) {
    var fullCost = 0;					// Setze die Kosten auf 0
    var myObjects = document.getElementsByTagName('TR'); // Hole alle Tabellenzeilen
    for (i = 0; i < myObjects.length; i++) {		// Gehe alle Tabellenzeilen durch
      var myObject = myObjects[i];				// Hole die Tabellenzeile
      myInnerObjects = myObject.getElementsByTagName('INPUT');	// Hole alle INPUTS innerhalb der Zeile
      if(myInnerObjects.length == 3) {				// Falls es genau 2 INPUTS sind, befinden wir uns in einer Zeile mit einer Einheit (im zweiten Element stehen die Heilkosten versteckt)
        if(myInnerObjects[0].checked) {					// Falls das erste Element ausgewählt ist (einheit soll geheilt werden)
          fullCost += parseInt(myInnerObjects[2].value);			// Addieren den zweiten Wert zu den Gesamtkosten
        }
      }
    }
    layerWrite('fullhealcosttop', I18N.numberFormat(fullCost, 0)); // Schreibe die Gesamtkosten formatiert oben in die Tabelle
    layerWrite('fullhealcostbottom', I18N.numberFormat(fullCost, 0)); // Schreibe die Gesamtkosten formatiert unten in die Tabelle

    if(fullCost > resAvailable && healWith != '5') {
      var marketString = '<a href="#" onclick="return(marketResWindow(\'Euch fehlen folgende Ressourcen:\', ' + (whichRes == 'erz' ? String(Math.max(0, fullCost - resAvailable)) : '0') + ', ' + (whichRes == 'gold' ? String(Math.max(0, fullCost - resAvailable)) : '0') + ', ' + (whichRes == 'holz' ? String(Math.max(0, fullCost - resAvailable)) : '0') + ', ' + (whichRes == 'nahrung' ? String(Math.max(0, fullCost - resAvailable)) : '0') + ', ' + (whichRes == 'silber' ? String(Math.max(0, fullCost - resAvailable)) : '0') + ', ' + (whichRes == 'erz' ? String(fullCost) : '0') + ', ' + (whichRes == 'gold' ? String(fullCost) : '0') + ', ' + (whichRes == 'holz' ? String(fullCost) : '0') + ', ' + (whichRes == 'nahrung' ? String(fullCost) : '0') + ', ' + (whichRes == 'silber' ? String(fullCost) : '0') + ', \'' + veggie + '\', \'location=' + loc + '~healwith=' + healWith + '~backto=' + backTo + '\', \'Heilen\'));">Fehlende Ressourcen</a>';
      $('mRHtop').innerHTML = marketString;
      $('mRHbottom').innerHTML = marketString;
    } else {
      $('mRHtop').innerHTML = '&nbsp;';
      $('mRHbottom').innerHTML = '&nbsp;';
    }
  }

  /**
    * Funktion, die für zwei gegebene Bewohnerzahlen die maximal erlaubte Goldwert-Differenz berechnet
    */
  function calcMaxGoldDifference(pts1, pts2) {
    return(Math.round(Math.pow(Math.min(pts1, pts2) * 2.5, 1.23) * Math.min(pts1, pts2) / Math.max(pts1, pts2)));
  }

  /**
    * Funktion die im Formular "calcgold" die Felder "partner1" und "partner2" ausliest, aus den dort stehenden
    * Bewohnerwerten die maximal erlaubten Golddifferenz in Handels/Abladeverhältnissen errechnet und sie
    * in das das Feld 'maxgold' schreibt.
    */
  function updateGoldDifference() {
    layerWrite('maxgold', 'Maximale Golddifferenz im Handelsverhältnis: ' + I18N.numberFormat(calcMaxGoldDifference(document.forms['calcgold'].elements['partner1'].value.replace('.', ''), document.forms['calcgold'].elements['partner2'].value.replace('.', '')), 0) + ' Gold');
  }

  /**
    * Richtet nachträglich eine Abfrage für ein Formular ein
    */
  function setupConfirmWarning(formName, confirmQuestion) {
    formElem = xGetElementById(formName);
    if(formElem) {
      formElem.onsubmit = function() {
      	return(confirm(confirmQuestion));
      }
    }
  }

  /**
    * Löscht eine Sicherheitsabfrage in einem Formular
    */
  function deleteConfirmWarning(formName) {
    formElem = xGetElementById(formName);
    if(formElem) {
      formElem.onsubmit = function() {
      	return(true);
      }
    }
  }

  /**
    * Funktion zum Löschen eines Knotens nach dem Namen
    */
  function deleteNodeById(nodeId) {
    delNode = xGetElementById(nodeId);		// Hole das gewünschte Element
    if(delNode) {				// Falls das Element gefunden wurde
      delNode.parentNode.removeChild(delNode);		// Lösche Knoten
    }
  }

  /**
    * Lösche alle Kindknoten eines Elements
    */
  function deleteContent(deleteObject) {
    doRefresh = is_opera && xStr(deleteObject);			// Check if we have to redraw after deleting everything
    if(xStr(deleteObject)) {					// Auf Ebene 0 haben wir nur den Namen übergeben - falls das der Fall ist:
      deleteObject = xGetElementById(deleteObject);			// Hole das eigentliche Objekt
    }
    if(deleteObject) {							// Falls wir ein zu löschendes Objekt gefunden haben
      if(deleteObject.nodeType != 3 && deleteObject.hasChildNodes()) {	// Falls es sich um keinen Textknoten handelt und der Knoten Kinder hat
        while (deleteObject.childNodes.length >= 1) deleteObject.removeChild(deleteObject.firstChild);// Lösche alle Kinder
      } else {									// Falls es sich um einen Textknoten handelt
      	// Netscape Navigator will das nicht ;)
      	if(!is_ns) deleteObject.nodeValue = "";							// Setze den Inhalt auf einen leeren String
      }
    }
    if(doRefresh) {					// Erzwinge Redraw des Basiselements in Opera
      xStyle('display', 'none', deleteObject); xStyle('display', 'block', deleteObject);
    }
  }

  /**
    * Berechne LP und Opferpunkte im Opfermenü
    */
  function sumLPandOP() {
    var sacrTable = xGetElementById('sacrTable');
    var rows = sacrTable.getElementsByTagName('TR');
    var sumLP = 0;
    var sumOP = 0;
    for (i = 0; i < rows.length; i++) {
      var curRow = rows[i];
      var cells = curRow.getElementsByTagName('TD');
      if(cells.length == 10) {
        var inputBox = cells[0].firstChild;
        if(inputBox.checked) {
          sumLP += parseFloat(String(curRow.lastChild.previousSibling.firstChild.nodeValue).replace(I18N.wordTable['THOUSANDS_SEP'], "").replace(I18N.wordTable['DECIMAL_POINT'], "."));
          sumOP += parseInt(String(curRow.lastChild.firstChild.nodeValue).replace(I18N.wordTable['THOUSANDS_SEP'], ""), 10);
        }
      }
    }

    writeText('sumlp', I18N.numberFormat(Math.floor(Math.round(sumLP * 10) / 10), 0));
    writeText('sumop', I18N.numberFormat(sumOP, 0));
  }

  function goToResearchPoints() {
    xHide('researchPointAreaTitle');
    xStyle('display', 'block', 'researchPointArea');
    xWinScrollTo(window, 0, 0, 300);
    return(false);
  }
  
  /**
    * Aktualisiert die Zeitanzeige bei Eier/Edelsteinsuche
    */
  function updateSearchTime(baseTime, elem) {
    var multiplier = elem.options[elem.selectedIndex].value;
    var tz = new Date();
    var curTime = new Date(tz.getTime() + checkTimeZone() + (baseTime * multiplier) * 1000);
    var theArr = new Array(2);				// Create new array for the creation of specific strings
    theArr[0] = seconds_to_countdown(baseTime * multiplier);					// Add the table ID as first and only element of the array
    theArr[1] = curTime.strftime('%a, %H:%M');
    writeText('searchTime', I18N.getSpecificString('DURATION_UNTIL_ENDTIME', theArr));
  }

/** FROM: http://www.csgnetwork.com/timezoneproginfo.html */
  function checkTimeZone() {
    var rightNow = new Date();
    var date1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
    var date2 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0);
    var temp = date1.toGMTString();
    var date3 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
    var temp = date2.toGMTString();
    var date4 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
    var hoursDiffStdTime = (date1 - date3); // Time zone difference
    var hoursDiffDaylightTime = (date2 - date4); // Time zone difference with DST
    return(hoursDiffDaylightTime - hoursDiffStdTime); // Return the ms between DST and normal. If != 0, DST is active
    /*if (hoursDiffDaylightTime == hoursDiffStdTime) {
      alert("Time zone is GMT " + hoursDiffStdTime + ".\nDaylight Saving Time is NOT observed here.");
    } else {
      alert("Time zone is GMT " + hoursDiffStdTime + ".\nDaylight Saving Time is observed here.");
    }*/
}

  /**
    * Berechnet die Chancen bei der Suche nach bestimmten Eiern
    */
  function calcEggChances() {
    var baseSums = Array(); baseSums[0] = 40; baseSums[1] = 25; baseSums[2] = 20; baseSums[3] = 10; baseSums[4] = 5;
    var addSum = 0; var eggsChecked = 5;
    if(!$('finddrei').checked) { baseSums[0] = 0; addSum += 1; eggsChecked--; }
    if(!$('findfsei').checked) { baseSums[1] = 0; addSum += 2; eggsChecked--; }
    if(!$('finddoei').checked) { baseSums[2] = 0; addSum += 3; eggsChecked--; }
    if(!$('findfrei').checked) { baseSums[3] = 0; addSum += 4; eggsChecked--; }
    if(!$('findfeei').checked) { baseSums[4] = 0; addSum += 5; eggsChecked--; }
    for(var i = 0; i <= 5; ++i) {
      if(baseSums[i] > 0) baseSums[i] += Math.round(addSum / eggsChecked);
    }
    writeText('drei_chance', String(baseSums[0]) + '%'); writeText('fsei_chance', String(baseSums[1]) + '%');
    writeText('doei_chance', String(baseSums[2]) + '%'); writeText('frei_chance', String(baseSums[3]) + '%');
    writeText('feei_chance', String(baseSums[4]) + '%');

  }

  /**
    * Berechnet die Chancen bei der Suche nach bestimmten Edelsteinen
    */
  function calcGemChances() {
    var baseSums = Array(); baseSums[0] = 40; baseSums[1] = 25; baseSums[2] = 20; baseSums[3] = 10; baseSums[4] = 5;
    var addSum = 0; var gemsChecked = 5;
    if(!$('findgreen').checked) { baseSums[0] = 0; addSum += 1; gemsChecked--; }
    if(!$('findyellow').checked) { baseSums[1] = 0; addSum += 2; gemsChecked--; }
    if(!$('findblue').checked) { baseSums[2] = 0; addSum += 3; gemsChecked--; }
    if(!$('findred').checked) { baseSums[3] = 0; addSum += 4; gemsChecked--; }
    if(!$('findwhite').checked) { baseSums[4] = 0; addSum += 5; gemsChecked--; }
    for(var i = 0; i <= 5; ++i) {
      if(baseSums[i] > 0) baseSums[i] += Math.round(addSum / gemsChecked);
    }
    writeText('gem_green_chance', String(baseSums[0]) + '%'); writeText('gem_yellow_chance', String(baseSums[1]) + '%');
    writeText('gem_blue_chance', String(baseSums[2]) + '%'); writeText('gem_red_chance', String(baseSums[3]) + '%');
    writeText('gem_white_chance', String(baseSums[4]) + '%');

  }


  /**
    * Funktion berechnet im Ritualmenü "Fruchtbarkeitsbeschwörung" das Gold, das man bei einem
    * erfolgreichen Ritualabschluss erhält.
    */
  function calcEggValueRitu(dreiVal, fseiVal, doeiVal, freiVal, feeiVal, dreiTimeFactor, fseiTimeFactor, doeiTimeFactor, freiTimeFactor, feeiTimeFactor) {

    var dreiSum = parseInt("0" + xGetElementById('sacr_drei').value, 10) * dreiVal;
    var fseiSum = parseInt("0" + xGetElementById('sacr_fsei').value, 10) * fseiVal;
    var doeiSum = parseInt("0" + xGetElementById('sacr_doei').value, 10) * doeiVal;
    var freiSum = parseInt("0" + xGetElementById('sacr_frei').value, 10) * freiVal;
    var feeiSum = parseInt("0" + xGetElementById('sacr_feei').value, 10) * feeiVal;
    var allSum = dreiSum + fseiSum + doeiSum + freiSum + feeiSum;
    var allDur = Math.floor(dreiSum / dreiTimeFactor + fseiSum / fseiTimeFactor + doeiSum / doeiTimeFactor + freiSum / freiTimeFactor + feeiSum / feeiTimeFactor);

    writeText('eggs_drei', I18N.numberFormat(dreiSum, 0));
    writeText('eggs_fsei', I18N.numberFormat(fseiSum, 0));
    writeText('eggs_doei', I18N.numberFormat(doeiSum, 0));
    writeText('eggs_frei', I18N.numberFormat(freiSum, 0));
    writeText('eggs_feei', I18N.numberFormat(feeiSum, 0));

    writeText('eggs_all', I18N.numberFormat(allSum, 0));
    writeText('rit_dur', seconds_to_countdown(allDur));
    writeText('rit_cost', I18N.numberFormat(allSum / 20, 0));

  }

  /**
    * Funktion, die die Drag+Drop Funktionalität der Monsterstärkenanzeige für die Karte realisiert
    */
  function setupMap(smin, smax) {
    monsterStrengthMin = smin;
    monsterStrengthMax = smax;
    xEnableDrag('hp_pr', null, thumbonDragMJStrength, null);
    xEnableDrag('hp_pl', null, thumbonDragMJStrength, null);
    enableDragWithHelper('dl4MapInfoTop', 'dl4MapInfo', null, function() { savePosition(4, xLeft('dl4MapInfo') - xScrollLeft(), xTop('dl4MapInfo') - xScrollTop()); });
  }

  /**
    * Funktion die beim Drag&Drop der Monsterstärke-Anzeiger aufgerufen wird
    */
  function thumbonDragMJStrength(e, mdx, mdy) {
    var newX = xLeft(e) + mdx;
    if (newX >= 0 && newX < xWidth(e.offsetParent) - xWidth(e) + 1) {
      hps = xGetElementById('hpshade');
      if(e.id == 'hp_pr' && newX < xLeft(xGetElementById('hp_pl')) - 1) {;
      	monsterStrengthMin = Math.round(newX / 2);
      	xGetElementById('new_smin').value = monsterStrengthMin;
      	xLeft(e, xLeft(e) + mdx);
        xLeft(hps, xLeft(e) + mdx);
      } else if(e.id == 'hp_pl' && newX > xLeft(xGetElementById('hp_pr')) + 1) {;
      	monsterStrengthMax = Math.round((newX + 11) / 2);
      	xGetElementById('new_smax').value = monsterStrengthMax;
        xLeft(e, xLeft(e) + mdx);
      }
      xWidth(hps, (monsterStrengthMax - monsterStrengthMin) * 2);
      writeText('mj_strength', String(monsterStrengthMin) + '% bis ' + String(monsterStrengthMax) + '%');
    }
  }

  /**
    * Funktion die ein Angebot nimmt, und dessen Daten im Missionsmenü in die entsprechenden Felder füllt
    */
  function fillLoadForm(tradeId, erz, gold, holz, nahrung, silber, drei, fsei, doei, frei, feei) {
    if(document.forms["loadform"].elements["load_erz"]) {
      if(drei > 0 || fsei > 0 || doei > 0 || frei > 0 || feei > 0) infoWindow('[span=dl4error]Die Eier aus dem Angebot wurden ignoriert, da Ihr Euch im Ressourcen-Beladungsmenü befindet[/span]', 'notLoaded');
      document.forms["loadform"].elements["load_erz"].value = String(erz);
      document.forms["loadform"].elements["load_gold"].value = String(gold);
      document.forms["loadform"].elements["load_holz"].value = String(holz);
      document.forms["loadform"].elements["load_nahrung"].value = String(nahrung);
      document.forms["loadform"].elements["load_silber"].value = String(silber);
    } else {
      if(erz > 0 || gold > 0 || holz > 0 || nahrung > 0 || silber > 0) infoWindow('[span=dl4error]Die Ressourcen aus dem Angebot wurden ignoriert, da Ihr Euch im Eier-Beladungsmenü befindet[/span]', 'notLoaded');
      document.forms["loadform"].elements["load_drei"].value = String(drei);
      document.forms["loadform"].elements["load_fsei"].value = String(fsei);
      document.forms["loadform"].elements["load_doei"].value = String(doei);
      document.forms["loadform"].elements["load_frei"].value = String(frei);
      document.forms["loadform"].elements["load_feei"].value = String(feei);
    }
    document.forms["loadform"].elements["use_loadallowance"].value = String(tradeId);
    document.forms["loadform"].elements["load"].value = "Einladen";
    var offerListImages = xGetElementsByTagName("img", xGetElementById('offerList'));
    for(var i = 0, len = offerListImages.length; i < len; ++i) {
      if(offerListImages[i].id.indexOf('img_') == 0) {
        if(offerListImages[i].id == "img_" + String(tradeId)) {
      	  offerListImages[i].src = useGrafikpfad + '/icons/20x20/start.gif';
        } else {
      	  offerListImages[i].src = useGrafikpfad + '/icons/20x20/next.gif';
        }
      }
    }
    return(false);
  }

  /**
    * Helferfunktion für das Aufladen von Ressourcen auf fremden Siedlungen
    */
  function loadAllowanceHelper() {
    if(document.forms['loadform'].elements['use_loadallowance'].value == 0) {
      alert('Ihr müsst ein Angebot wählen!');
      return(false);
    }

    disableFormElement('loadform', 'load', 'Einladen...');
    document.forms['loadform'].elements['loadaction'].value = 'load';
    document.forms['loadform'].submit();
    return(true);
  }

  /**
    * Wenn im Tribunal ein Amtsinhaber den Subparagraphen ändert bei einem Fall, wird diese Funktion aufgerufen.
    * @Hacker: Nein, dir hilft der Link alleine trotzdem nicht :)
    */
  function changeSubParagraph(tid) {
    var subChooserSelect = xGetElementById('subchooser');
    location.href = '?location=tribunal&area=trialdetails&tid=' + String(tid) + '&action=subpara&setsubparagraph=' + subChooserSelect.options[subChooserSelect.selectedIndex].value;
  }

  /**
    * Funktion zum erstellen eines Marktplatz-Link-Fensters, mit Ressourcenanzeige, Bonustext und bei Bedarf Zwangsbacklink
    */
  function marketResWindow(marketText, erz, gold, holz, nahrung, silber, full_erz, full_gold, full_holz, full_nahrung, full_silber, veggie, backLink, backName, additionalText, sourceForm, inputTypes) {
    var marketShown = xGetElementById('dl4MarketLink');

    var newMarketContentNode = xGetElementById('dl4MarketContent');

    if(!marketShown) {						// Falls der Marktlink noch nicht angezeigt wird
      mainObject = xGetElementById(mainObjectId);					// Hole DL4-Content

      var newMarketLinkNode = document.createElement("div");			// Erstelle Marktlink-DIV
      newMarketLinkNode.id = 'dl4MarketLink';					// Setze ID für Marktlink
      newMarketLinkNode.className = 'dl4WideWindow';				// Setze Klasse für Marktlink

      var newMarketCloseNode = makeAbortButton('dl4MarketLink', 'dl4MarketClose'); // Erstelle Schliessen-Button für Marktlink

      var newMarketDragNode = document.createElement("div");			// Erstelle Dragbar-DIV
      newMarketDragNode.id = 'dl4MarketLinkDragBar';				// Setze ID für Dragbar
      newMarketDragNode.className = 'dl4WideWindowDragBar';			// Setze Klasse für Dragbar

      newMarketContentNode = document.createElement("div");			// Erstelle Markttext-DIV
      newMarketContentNode.id = 'dl4MarketContent';				// Setze ID für Markttext
      newMarketContentNode.className = 'dl4WideWindowContent';			// Setze Klasse für Markttext

      var newMarketContentLeftNode = document.createElement("div");		// Erstelle Markttext-DIV (links, Text)
      newMarketContentLeftNode.id = 'dl4MarketContentLeft';			// Setze ID für DIV links
      newMarketContentLeftNode.style.cssFloat = 'left';				// Float-Mode on, Baby
      newMarketContentLeftNode.style.styleFloat = 'left';			// Float-Mode on, Baby (IE Honk)
      newMarketContentLeftNode.style.width = '50%';				// Setze die Breite auf 50%;

      var newMarketContentRightNode = document.createElement("div");		// Erstelle Markttext-DIV (rechts, Ressourcen)
      newMarketContentRightNode.id = 'dl4MarketContentRight';			// Setze ID für DIV rechts
      newMarketContentRightNode.style.cssFloat = 'left';			// Float-Mode on, Baby
      newMarketContentRightNode.style.styleFloat = 'left';			// Float-Mode on, Baby (IE Honk)
      newMarketContentRightNode.style.width = '45%';				// Etwas kleiner als links, sicher ist sicher, sonst bricht der float um
      newMarketContentRightNode.style.paddingLeft = '10px';			// Und ein wenig padding :]


      newMarketLinkNode.appendChild(newMarketDragNode);				// Füge Content Node hinzu
      newMarketLinkNode.appendChild(newMarketContentNode);			// Füge Content Node hinzu
      newMarketLinkNode.appendChild(newMarketCloseNode);			// Füge X hinzu
      newMarketContentNode.appendChild(newMarketContentLeftNode);		// Füge Content Node Bereich Links hinzu
      newMarketContentNode.appendChild(newMarketContentRightNode);		// Füge Content Node Bereich Rechts hinzu
      mainObject.appendChild(newMarketLinkNode);				// Füge Marktlink hinzu

      xMoveTo('dl4MarketLink', 200, xScrollTop() + 200);
      xEnableDrag('dl4MarketLinkDragBar', null, new Function('ele', 'dx', 'dy', 'eveObj', 'xMoveTo(\'dl4MarketLink\', xLeft(\'dl4MarketLink\') + dx, xTop(\'dl4MarketLink\') + dy);'), null);
    }

    globalTextSpeed = 0;
    deleteContent('dl4MarketContentLeft');
    deleteContent('dl4MarketContentRight');
    addBBCode('dl4MarketContentLeft', marketText + (xDef(additionalText) && additionalText != null ? additionalText : '\n\n'));
    addBBCode('dl4MarketContentRight', '[img]' + useGrafikpfad + '/icons/res/erz.gif[/img][b] ' + I18N.getSpecificString('ORE') + ':[/b] ' + I18N.numberFormat(erz, 0) + '\n[img]' + useGrafikpfad + '/icons/res/gold.gif[/img][b] ' + I18N.getSpecificString('GOLD') + ':[/b] ' + I18N.numberFormat(gold, 0) + '\n[img]' + useGrafikpfad + '/icons/res/holz.gif[/img][b] ' + I18N.getSpecificString('WOOD') + ':[/b] ' + I18N.numberFormat(holz, 0) + '\n[img]' + useGrafikpfad + '/icons/res/nahrung_' + veggie + '.gif[/img][b] ' + I18N.getSpecificString('FOOD') + ':[/b] ' + I18N.numberFormat(nahrung, 0) + '\n[img]' + useGrafikpfad + '/icons/res/silber.gif[/img][b] ' + I18N.getSpecificString('SILVER') + ':[/b] ' + I18N.numberFormat(silber, 0));

    if(full_erz > 0 || full_gold > 0 || full_holz > 0 || full_nahrung > 0 || full_silber > 0) {
      var newMarketLinkInputImg = document.createElement('img');			// Erstelle Button
      newMarketLinkInputImg.src = useGrafikpfad + '/buttons/zummarktplatz.gif';
      newMarketLinkInputImg.alt = 'Zum Marktplatz';
      enableHoverImageDL(newMarketLinkInputImg);
      var newMarketLinkInputSubmit = document.createElement('a');		// Erstelle Button
      newMarketLinkInputSubmit.href = '#';
      newMarketLinkInputSubmit.style.marginLeft = '100px';
      Event.observe(newMarketLinkInputSubmit, 'click', function() { document.forms['marketMissingForm'].submit(); });
      newMarketLinkInputSubmit.appendChild(newMarketLinkInputImg);
      var newMarketLinkInputForm = document.createElement('form');		// Erstelle Button
      newMarketLinkInputForm.action = '?location=markt&need_res=' + String(full_erz) + '_' + String(full_gold) + '_' + String(full_holz) + '_' + String(full_nahrung) + '_' + String(full_silber) + '&backlink=' + backLink + '&backtowhat=' + backName.replace(' ', '%20');
      newMarketLinkInputForm.method = 'post';
      newMarketLinkInputForm.name = 'marketMissingForm';
      newMarketLinkInputForm.id = 'marketMissingForm';
      newMarketLinkInputForm.appendChild(newMarketLinkInputSubmit);
      xGetElementById('dl4MarketContentLeft').appendChild(newMarketLinkInputForm);
      xStyle('display', 'block', newMarketLinkInputForm, newMarketLinkInputSubmit, newMarketLinkInputImg);				// Der IE braucht mal wieder einen Extra-Tritt
      
      if(xDef(sourceForm)) {
      	copyFormData(sourceForm, newMarketLinkInputForm, inputTypes);
      }
    }

    return(false);
  }

  /**
    * Erstellt einen Abort-Button für ein Fenster (Grafik + Abbruch-Funktionalität)
    * Der Funktionsaufruf beim Klicken kann übergeben werden per new Function, oder es wird nur
    * ein String übergeben - in diesem Fall wird das Element mit der übergebenen ID einfach gelöscht
    */
  function makeAbortButton(functionCallOnClose, buttonId) {

    if(xStr(functionCallOnClose)) functionCallOnClose = new Function('deleteNodeById(\'' + functionCallOnClose + '\');'); // Falls nur ein String übergeben wurde, ist dies der Name des Elements, dass durch den Button geschlossen wird
    var abortButton = document.createElement("div");			// Erstelle Button-DIV
    abortButton.id = buttonId;					// Setze ID für Button
    abortButton.className = 'dl4AbortButton';			// Setze Klasse für Button

    var abortImage = createImageNode(useGrafikpfad + '/buttons/20x20/redcross.gif', '', I18N.getSpecificString('ABORT'), I18N.getSpecificString('ABORT'));		// Erstelle Bild für Button
    enableHoverImageDL(abortImage);				// Ermögliche Hovering für Schließen-Button
    Event.observe(abortImage, 'click', functionCallOnClose);
    //abortImage.onclick = functionCallOnClose;			// Setze den Funktionsaufruf für den übergebenen Funktionsaufruf

    abortButton.appendChild(abortImage);			// Füge Bild in <div> ein

    return(abortButton);
  }

  /**
    * Funktion die einen Bildknoten mit URL, alternativem Text und Titeltext erstellt
    */
  function createImageNode(imgSrc, imgId, altText, titleText) {
    imageNode = document.createElement('img');		// Erstelle Knoten für Bild
    imageNode.src = imgSrc;				// Setze URL für Bild
    imageNode.id = imgId;				// Setze ID für Bild
    imageNode.alt = altText;				// Setze Alternativtext für Bild
    imageNode.title = titleText;			// Setze Titel für Bild
    return(imageNode);					// Gebe Knoten zurück
  }

  /**
    * Funktion zum erstellen eines Marktplatz-Link-Fensters, mit Ressourcenanzeige, Bonustext und bei Bedarf Zwangsbacklink
    */
  function infoWindow(infoText, windowName) {

    var infoWindowShown = xGetElementById(windowName);

    if(!infoWindowShown) {						// Falls das Fenster noch nicht angezeigt wird
      mainObject = xGetElementById(mainObjectId);				// Hole DL4-Content

      var newInfoWindowNode = document.createElement("div");		// Erstelle Window-DIV
      newInfoWindowNode.id = windowName;				// Setze ID für Window
      newInfoWindowNode.className = 'dl4WideWindow';			// Setze Klasse für Window

      var newInfoWindowCloseNode = makeAbortButton(windowName, windowName + 'Close'); // Erstelle Close-Button

      var newInfoWindowDragNode = document.createElement("div");	// Erstelle Window-Inhalt-DIV
      newInfoWindowDragNode.id = windowName + 'DragBar';		// Setze ID für Markttext
      newInfoWindowDragNode.className = 'dl4WideWindowDragBar';	// Setze Klasse für Markttext

      var newInfoWindowContentNode = document.createElement("div");	// Erstelle Window-Inhalt-DIV
      newInfoWindowContentNode.id = windowName + 'Content';		// Setze ID für Markttext
      newInfoWindowContentNode.className = 'dl4WideWindowContent';	// Setze Klasse für Markttext

      newInfoWindowNode.appendChild(newInfoWindowDragNode);		// Füge Content Node hinzu
      newInfoWindowNode.appendChild(newInfoWindowCloseNode);		// Füge X hinzu
      newInfoWindowNode.appendChild(newInfoWindowContentNode);		// Füge Content Node hinzu
      mainObject.appendChild(newInfoWindowNode);			// Füge Marktlink hinzu
      infoWindowShown = newInfoWindowNode;				// Weise der Rückgabevariable das Info-Fenster-Objekt hinzu

      xEnableDrag(newInfoWindowDragNode, null, new Function('ele', 'dx', 'dy', 'eveObj', 'xMoveTo(\'' + windowName + '\', xLeft(\'' + windowName + '\') + dx, xTop(\'' + windowName + '\') + dy);'), null);

      xMoveTo(newInfoWindowNode, Math.max(0, Math.ceil((xClientWidth() - xWidth(newInfoWindowNode)) / 2)), xScrollTop() + Math.ceil((xClientHeight() - xHeight(newInfoWindowNode)) / 2));
    }

    globalTextSpeed = 0;
    deleteContent(windowName + 'Content');
    addBBCode(windowName + 'Content', infoText);

    return(infoWindowShown);
  }

  /**
    * Funktion die einen Template-Namen abfragt und wenn er angegeben wird, zur entsprechenden Seite weiterleitet
    */
  function saveTemplateWithPrompt(unitid, itemkeys) {
    templatename = prompt(I18N.getSpecificString('ENTER_TEMPLATE_NAME'), '');
    if(templatename != null) location.href='?location=ausbilden&dotraining=template&unitid=1&unitname=' + templatename + '&getunittype=' + unitid + itemkeys;
  }

  /**
    * Funktion, die Heilkosten berechnet bei verschiedenen ausgewählten Heilzaubern
    */
  function calcHealCost(rep) {
    var erzCost = 0;					// Erstelle
    var goldCost = 0;					//   Variablen
    var holzCost = 0;					//      zum Aufnehmen
    var nahrungCost = 0;				//        der
    var silberCost = 0;					//          Gesamtkosten

    var eachCosts = String(document.forms['allheal'].elements[0].value).split('_'); // Hole die Res die in der Siedlung vorhanden sind aus dem allerersten Element
    var siedlungErz = parseInt(eachCosts[0], 10);	// Parse
    var siedlungGold = parseInt(eachCosts[1], 10);	//    die Zahlen
    var siedlungHolz = parseInt(eachCosts[2], 10);	//      in
    var siedlungNahrung = parseInt(eachCosts[3], 10);	//        entsprechende
    var siedlungSilber = parseInt(eachCosts[4], 10);	//          Variablen
  	
    for(var i = 3, len = document.forms['allheal'].elements.length - 1; i < len; i += 3) { // Gehe die Elemente des Formulars durch (Starte beim 3. Element, was entweder bereits das letzte Element ist (keine Einheit vorhanden), oder die Kosten der ersten Einheitsausrüstung)
      if(document.forms['allheal'].elements[i].checked == true) { // Falls die Einheit ausgerüstet werden soll
      	eachCosts = String(document.forms['allheal'].elements[i + 1].value).split('_'); // Splitte den Kostenarray der versteckt ist
      	erzCost += parseInt(eachCosts[0], 10); goldCost += parseInt(eachCosts[1], 10); holzCost += parseInt(eachCosts[2], 10);  // Parse
      	nahrungCost += parseInt(eachCosts[3], 10); silberCost += parseInt(eachCosts[4], 10); // ... die Variablen und füge sie den Gesamtkosten hinzu
      }
    }

    var mRU = $('missingResUnitheal');
    if(mRU) {
      if(erzCost > siedlungErz || goldCost > siedlungGold || holzCost > siedlungHolz || nahrungCost > siedlungNahrung || silberCost > siedlungSilber) { // Falls in der Siedlung irgendeine Ressource zu fehlen scheint
      	if(rep) {
      	  mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'' + I18N.getSpecificString('REPAIR_MARKET_RES') + '\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + ', \'' + String(document.forms['allheal'].elements[1].value) + '\', \'' + I18N.getSpecificString('DO_REPAIR') + '\', null, \'allheal\', new Array(\'hidden\', \'checkbox\')));">' + I18N.getSpecificString('MISSING_RES') + '</a>';
      	} else {
      	  mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'' + I18N.getSpecificString('HEAL_MARKET_RES') + '\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + ', \'' + String(document.forms['allheal'].elements[1].value) + '\', \'' + I18N.getSpecificString('HEAL_UNITS') + '\', null, \'allheal\', new Array(\'hidden\', \'checkbox\')));">' + I18N.getSpecificString('MISSING_RES') + '</a>';
      	}
      } else {
        mRU.innerHTML = '&nbsp;';
      }
    }

  }

  /**
    * Funktion die die Kosten berechnet, bei Markieren von mehreren Einheiten. Beim Umrüsten, Zauber erlernen, Eiersuchen und auch beim Edelsteinsuchen
    *
    * @param multipleType Defines the type of multiple selection (1 = learn magic, 2 = equip units, 3 = eggsearch, 4 = gemsearch)
    */
  function calcMultipleUnitCosts(multipleType) {
    var erzCost = 0;					// Erstelle
    var goldCost = 0;					//   Variablen
    var holzCost = 0;					//      zum Aufnehmen
    var nahrungCost = 0;				//        der
    var silberCost = 0;					//          Gesamtkosten

    var eachCosts = String(document.forms['equipmultiple'].elements[0].value).split('_'); // Hole die Res die in der Siedlung vorhanden sind aus dem allerersten Element
    var siedlungErz = parseInt(eachCosts[0], 10);	// Parse
    var siedlungGold = parseInt(eachCosts[1], 10);	//    die Zahlen
    var siedlungHolz = parseInt(eachCosts[2], 10);	//      in
    var siedlungNahrung = parseInt(eachCosts[3], 10);	//        entsprechende
    var siedlungSilber = parseInt(eachCosts[4], 10);	//          Variablen

    for(var i = 3, len = document.forms['equipmultiple'].elements.length - 1; i < len; i += 2) { // Gehe die Elemente des Formulars durch (Starte beim 3. Element, was entweder bereits das letzte Element ist (keine Einheit vorhanden), oder die Kosten der ersten Einheitsausrüstung)
      if(document.forms['equipmultiple'].elements[i + 1].checked == true) { // Falls die Einheit ausgerüstet werden soll
      	eachCosts = String(document.forms['equipmultiple'].elements[i].value).split('_'); // Splitte den Kostenarray der versteckt ist
      	erzCost += parseInt(eachCosts[0], 10); goldCost += parseInt(eachCosts[1], 10); holzCost += parseInt(eachCosts[2], 10);  // Parse
      	nahrungCost += parseInt(eachCosts[3], 10); silberCost += parseInt(eachCosts[4], 10); // ... die Variablen und füge sie den Gesamtkosten hinzu
      }
    }

    if($('erzEquipCost')) writeText('erzEquipCost', I18N.numberFormat(erzCost, 0)); // Schreibe
    if($('goldEquipCost')) writeText('goldEquipCost', I18N.numberFormat(goldCost, 0)); // die neuen
    if($('holzEquipCost')) writeText('holzEquipCost', I18N.numberFormat(holzCost, 0)); // Kosten
    if($('nahrungEquipCost')) writeText('nahrungEquipCost', I18N.numberFormat(nahrungCost, 0)); // in die entsprechenden
    if($('silberEquipCost')) writeText('silberEquipCost', I18N.numberFormat(silberCost, 0)); // Felder

    var mRU = $('missingResUnitchange');
    if(mRU) {
      if(erzCost > siedlungErz || goldCost > siedlungGold || holzCost > siedlungHolz || nahrungCost > siedlungNahrung || silberCost > siedlungSilber) { // Falls in der Siedlung irgendeine Ressource zu fehlen scheint
        if(multipleType == 1) {
      	  mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'Euch fehlen folgende Ressourcen zum Erlernen des Zaubers:\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + String(document.forms['equipmultiple'].elements[1].value) + '~savemagic=yes~domultiple=yes\',\'Zauber erlernen\',null,\'equipmultiple\',new Array(\'checkbox\',\'hidden\')));">Fehlende Ressourcen</a>';
        } else if(multipleType == 2) {
          mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'Euch fehlen folgende Ressourcen zum Ausrüsten:\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + String(document.forms['equipmultiple'].elements[1].value) + '~saveitems=yes~domultiple=yes\',\'Ausrüsten\',null,\'equipmultiple\',new Array(\'checkbox\',\'hidden\')));">Fehlende Ressourcen</a>';
        } else if(multipleType == 3) {
          mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'Euch fehlen folgende Ressourcen zum Eier suchen:\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + String(document.forms['equipmultiple'].elements[1].value) + '~multiple=yes\',\'Eier suchen\',null,\'equipmultiple\',new Array(\'checkbox\',\'hidden\')));">Fehlende Ressourcen</a>';
        } else if(multipleType == 4) {
          mRU.innerHTML = '<a href="#" onclick="return(marketResWindow(\'Euch fehlen folgende Ressourcen zum Edelsteine suchen:\', ' + String(Math.max(0, erzCost - siedlungErz)) + ', ' + String(Math.max(0, goldCost - siedlungGold)) + ', ' + String(Math.max(0, holzCost - siedlungHolz)) + ', ' + String(Math.max(0, nahrungCost - siedlungNahrung)) + ', ' + String(Math.max(0, silberCost - siedlungSilber)) + ', ' + erzCost + ', ' + goldCost + ', ' + holzCost + ', ' + nahrungCost + ', ' + silberCost + String(document.forms['equipmultiple'].elements[1].value) + '~multiple=yes\',\'Edelsteine suchen\',null,\'equipmultiple\',new Array(\'checkbox\',\'hidden\')));">Fehlende Ressourcen</a>';
        }
      } else {
        mRU.innerHTML = '&nbsp;';
      }
    }

  }
  
  /**
    * Ermöglicht das Übertragen der Formulardaten von einem Formular in ein anderes
    */
  function copyFormData(sourceForm, targetForm, copyTypes) {
    if(!xDef(copyTypes)) var copyTypes = $A(new Array('radio', 'checkbox', 'text', 'select-one')); // Falls keine zu kopierenden Typen angegeben sind, kopiere folgende
    sourceForm = $(sourceForm);
    targetForm = $(targetForm);
    for(var i = 0, len = sourceForm.elements.length; i < len; ++i) {	// Gehe alle Elemente des Quellformulars durch
      if(copyTypes.indexOf(sourceForm.elements[i].type) != -1) {
      	var newInput = document.createElement('input');
      	newInput.type = 'hidden';
      	newInput.name = sourceForm.elements[i].name;
      	if(sourceForm.elements[i].type == 'radio' && sourceForm.elements[i].checked == true) {
      	  newInput.value = sourceForm.elements[i].value;
      	  targetForm.appendChild(newInput);
      	} else if(sourceForm.elements[i].type == 'checkbox' && sourceForm.elements[i].checked == true) {
      	  if(sourceForm.elements[i].value) newInput.value = sourceForm.elements[i].value; else newInput.value = 'on';
      	  targetForm.appendChild(newInput);
      	} else if(sourceForm.elements[i].type == 'text' || sourceForm.elements[i].type == 'hidden') {
      	  newInput.value = sourceForm.elements[i].value;
      	  targetForm.appendChild(newInput);
      	} else if(sourceForm.elements[i].type == 'select-one') {
      	  newInput.value = sourceForm.elements[i].options[sourceForm.elements[i].selectedIndex].value;
      	  targetForm.appendChild(newInput);
      	}
      }
    }
  }

  /**
    * Function to display tooltip with current mouse coordinates (lower left corner of given element at mouse position)
    */
  //function showTT(curEvent, elemId) {
  function showTT(curEvent) {

    var o = $(this.ttId);

    xStyle('visibility', 'hidden', o);
    xStyle('display', 'block', o);
    if(!this.isFixed) {
      var y = curEvent.pageY + 20;
      var x = curEvent.pageX + 20;
      var maxX = xClientWidth() + xScrollLeft() - xWidth(o);
      var maxY = xClientHeight() + xScrollTop() - xHeight(o);
      if(x > maxX) x = x - xWidth(o) - 40;
      if(y > maxY) y = y - xHeight(o) - 40;
      if(x < 0) x = curEvent.pageX + 20 - Math.floor(xWidth(o) / 2) + 40;
      if(y < 0) y = curEvent.pageY + 20 - Math.floor(xHeight(o) / 2) + 40;
      xTop(o, y);
      xLeft(o, x);
    }
    xStyle('visibility', 'visible', o);

    return(false);
  }

  /**
    * Function to hide tooltip
    */
  function hideTT(curEvent) {
    xStyle('display', 'none', this.ttId);
    return(false);
  }

  /**
    * Falls bei einer Gruppenspionage ein Nicht-Kriegsgegner anvisiert wird, müssen wir in der dynamischen Version
    * diese Funktion ausführen, damit das Formular erneut abgeschickt wird, aber ein weiteres Element zugefügt wird,
    * dass die Mehrkosten bestätigt.
    */
  function prepareGroupspyForm() {
    var spyForm = $('groupspyform');			// Hole das Spionage-Formular
    if(spyForm) {					// Falls es existiert
      addInputElement(spyForm, 'hidden', 'paymore', 'yes');	// Erstelle verstecktes Eingabeelement
      spyForm.submit();						// Verschicke Formular
    }
  }

  /**
    * Fügt an ein gegebenes Element ein input-Element an mit den gegebenen Eigenschaften
    */
  function addInputElement(formElem, inpType, inpName, inpVal) {
    var newInput = document.createElement("input");	// Erstelle neues Input-Element
    newInput.type = inpType;				// Setze Typ
    newInput.name = inpName;				// Setze Name
    newInput.value = inpVal;				// Setze Wert
    formElem.appendChild(newInput);			// Füge neues Element an das übergebene Element an
    return(newInput);					// Gebe erstelltes Element zurück
  }

  /**
    * Funktion "enableHoverSelf" (abgekürzt zum Trafficsparen ;)
    * Aktiviert Hover-Bild bei mouseover und entfernt den Aufruf von sich selbst
    */
  function eHS(imgElem) {
    if(!imgElem.outImg) {			// Falls das Bild noch nicht für Hovering vorbereitet ist
      enableHoverImageDL(imgElem);			// Ermögliche Bildhovering
      imgOnMouseoverManual(imgElem);			// Aktiviere Hovering manuell, da der Eventhandler den wir in der Zeile darüber eingerichtet haben erst beim nächsten onmouseover aktiviert wird
    }
  }

  /**
    * Ermöglicht Hover-Bild
    */
  function enableHoverImage(imgElem, hoverImgSrc) {
    var imgNode = xGetElementById(imgElem);			// Hole IMG-Node (wenn es nicht schon eins ist)
    if(imgNode) {
      imgNode.outImg = new Object();				// Erstelle Bild-Objekt für normale Anzeige
      imgNode.outImg.src = imgNode.src;			// Erstelle Bild-URL für Bild, wenn die Maus außerhalb des Links ist

      imgNode.overImg = new Image();				// Erstelle Bild-Objekt für Hover
      imgNode.overImg.src = hoverImgSrc;			// Erstelle Bild-URL für Bild, wenn die Maus sich darüber befindet
      
      Event.observe(imgNode, 'mouseover', imgOnMouseover);	// Erstelle Event-Handler für onmouseover
      Event.observe(imgNode, 'mouseout', imgOnMouseout);	// Erstelle Event-Handler für onmouseout

      return(imgNode);						// Gebe IMG-Node zurück
    }
    return(null);
  }

  /**
    * Ermöglicht Hover-Bild
    */
  function enableHoverImageDL() {
    for(var i = 0, len = arguments.length; i < len; ++i) {
      var imgNode = xGetElementById(arguments[i]);		// Hole IMG-Node (wenn es nicht schon eins ist)
      if(imgNode) {
        imgNode.outImg = new Object();				// Erstelle Bild-Objekt für normale Anzeige
        imgNode.outImg.src = imgNode.src;			// Erstelle Bild-URL für Bild, wenn die Maus außerhalb des Links ist

        imgNode.overImg = new Image();				// Erstelle Bild-Objekt für Hover
        imgNode.overImg.src = imgNode.src.replace(/\.(png|gif|jpg)/g, '_a.$1');	// Erstelle Bild-URL für Bild, wenn die Maus sich darüber befindet

      	Event.observe(imgNode, 'mouseover', imgOnMouseover);	// Erstelle Event-Handler für onmouseover
      	Event.observe(imgNode, 'mouseout', imgOnMouseout);	// Erstelle Event-Handler für onmouseout

      }
    }
  }

  /**
    * Ermöglicht Hover-Bild
    */
  function enableMenuImages() {
    for(var i = 0, len = arguments.length; i < len; i += 2) {
      var imgNode = xGetElementById(arguments[i]);		// Hole IMG-Node (wenn es nicht schon eins ist)
      if(imgNode) {
        imgNode.outImg = new Object();				// Erstelle Bild-Objekt für normale Anzeige
        imgNode.outImg.src = imgNode.src;			// Erstelle Bild-URL für Bild, wenn die Maus außerhalb des Links ist

        imgNode.overImg = new Image();				// Erstelle Bild-Objekt für Hover
        imgNode.overImg.src = imgNode.src.replace(/\.(png|gif|jpg)/g, '_a.$1');	// Erstelle Bild-URL für Bild, wenn die Maus sich darüber befindet
        
        imgNode.menuString = String(arguments[i + 1]);

      	Event.observe(imgNode, 'mouseover', imgOnMouseover);	// Erstelle Event-Handler für onmouseover
      	Event.observe(imgNode, 'mouseout', imgOnMouseout);	// Erstelle Event-Handler für onmouseout

      }
    }
  }

  /**
    * onmouseout Event-Handler Funktion für Bilder
    */
  function imgOnMouseout(ev) {
    if(this.outImg) {
      this.src = this.outImg.src;
      if(this.menuString) $('dl4MainMenuTop').innerHTML = menuStringDefault;
    }
    return(false);
  }

  /**
    * onmouseover Event-Handler Funktion für Bilder
    */
  function imgOnMouseover(ev) {
    if(this.overImg && this.overImg.complete) {
      this.src = this.overImg.src;
      if(this.menuString) $('dl4MainMenuTop').innerHTML = this.menuString;
    }
    return(false);
  }

  /**
    * onmouseover manueller aufruf
    */
  function imgOnMouseoverManual(imgElem) {
    if(imgElem.overImg) {
      imgElem.src = imgElem.overImg.src;
    }
    return(false);
  }

  /**
    * Hilfsfunktion bei den Taktikeinstellungen für mehrere Einheiten
    */
  function getTactics() {
    var uses = document.forms['changetactic'].elements['usetactic'];
    for(var i = 0, len = uses.length; i < len; ++i) {
      if(uses[i].checked) {
      	document.forms['equipmultiple'].elements['usetactic'].value = uses[i].value;
      }
    }
    document.forms['equipmultiple'].submit();
  }

  /**
    * Funktion die einen Hyperlink-Button mit Bild erstellt, mit optionalem onmouseover-Bild,
    * optionaler onclick Aktion für den Hyperlink und optionalem Style für das Bild.
    */
  function createHrefButton(imgSrc, hrefUrl, clickAction, styleOptions) {
    var newHyperlinkNode = document.createElement("a");		// Erstelle Hyperlink
    var newImgNode = document.createElement("img");		// Erstelle Bild-Tag für Hyperlink
    newImgNode.outImg = new Image();				// Erstelle Bild-Objekt für normale Anzeige
    newImgNode.outImg.src = imgSrc;				// Erstelle Bild-URL für Bild, wenn die Maus außerhalb des Links ist
    newImgNode.src = imgSrc;					// Zeige aktuelles Bild
    xStyle('border', '0px', newImgNode);			// Rand setzen wir für alle Bilder innerhalb von Hyperlinks auf 0
    enableHoverImageDL(newImgNode);				// Ermögliche Hovering für Bild
    var styleHash = $H(styleOptions);				// Erstelle Hash-Array aus Style-Optionen
    styleHash.each(function(pair) { xStyle(pair.key, pair.value, newHyperlinkNode); }); // Setze alle Styles für das Hyperlink-Element, die übergeben wurden
    newHyperlinkNode.href = hrefUrl;				// Setze URL für Hyperlink
    if(clickAction) newHyperlinkNode.onclick = clickAction;	// Füge die angegebene Aktion als onclick-Aktion für den Bestätigungsbutton ein
    newHyperlinkNode.appendChild(newImgNode);			// Füge Bild als link ein
    return(newHyperlinkNode);					// Gebe Hyperlink-Node zurück
  }

  /**
    * Erstellt bei einer "ask"-Antwort des Servers das Fenster, dass die entsprechende Frage stellt
    */
  function createQuestionWindow(responseData) {
    infoWindow(responseData.message, 'defaultQuestionWindow');	// Gebe Frage aus in ein entsprechendes Fenster
    var qWC = xGetElementById('defaultQuestionWindowContent');	// Hole das betroffene Fensterinhalt-Div
    addLineBreak(qWC);						// Füge einen Zeilenumbruch hinzu
    var qW = document.createElement("div");			// Erstelle DIV für Zentrierung
    qWC.appendChild(qW);					// Füge DIV in den Fenster-Inhalt ein
    xStyle('width', '100%', qW);				// Setze DIV auf volle Breite
    xStyle('textAlign', 'center', qW);				// Setze DIV-Text auf zentriert

    /* Erstelle Bestätigungs-Button
     *
     * Ist die Aktion, die in responseData gespeichert ist, ein String,
     * werden wir den Funktionsaufruf als String betrachten, ansonsten als direktes Funktionsobjekt */
    var newHyperlinkNode = createHrefButton(useGrafikpfad + '/buttons/36x36/greencheck.gif',
    						'#',
    						(typeof(responseData.performAction) == 'string' ? new Function(responseData.performAction + ' deleteNodeById(\'defaultQuestionWindow\'); return(false);') : function() { responseData.performAction();  deleteNodeById('defaultQuestionWindow'); return(false); }),
    						{ 'marginRight': '10px' });
    qW.appendChild(newHyperlinkNode);				// Füge Hyperlink ins Dokument ein

    /* Erstelle große Version des Abbrechen-Buttons */
    newHyperlinkNode = createHrefButton(useGrafikpfad + '/buttons/36x36/redcross.gif',
    						'#',
    						(typeof(responseData.abortAction) == 'undefined' ? function() { deleteNodeById('defaultQuestionWindow'); return(false); } : function() { responseData.abortAction();  deleteNodeById('defaultQuestionWindow'); return(false); }),
    						{ 'marginLeft': '10px' });
    qW.appendChild(newHyperlinkNode);				// Füge Hyperlink ins Dokument ein

  }

  /**
    * Konstruktor des Ergebnisdaten-Objektes, das Rückgabewert, Antwortklasse und Nachrichtentext beinhaltet
    */
  function responseDataObject(retval, rClass, xmlDataOfReturnTag) {
    this.returnVal = retval;			// Setze Rückgabewert
    this.responseClass = rClass;		// Setze Antwortklasse
    this.message = (xmlDataOfReturnTag.firstChild != undefined ? xmlDataOfReturnTag.firstChild.data : '');			// Setze Nachrichtentext
    if(this.responseClass == 'ask') {		// Falls es sich um eine Frage handelt, die man bestätigen kann
      this.performAction = xmlDataOfReturnTag.getAttribute('action'); // Speichere hier die URL, auf die man bei "JA" weitergeleitet wird
    } else if(this.responseClass == 'forward') { // Falls es sich um eine Weiterleitung handelt
      this.fwdUrl = this.message;			// Setze Nachricht als weiterzuleitende URL
    } else if(this.responseClass == 'rewrite') { // Falls es sich um eine Veränderung von bestehendem Inhalt handelt
      this.newClass = xmlDataOfReturnTag.getAttribute('newclass'); // Setze die neue Klasse des zu verändernden Objektes
    } else if(this.responseClass == 'chgfx') { // Falls es sich um eine Veränderung von bestehendem Inhalt handelt
      this.newSrc = xmlDataOfReturnTag.getAttribute('newsrc'); // Setze die neue Klasse des zu verändernden Objektes
      this.updateHover = (xmlDataOfReturnTag.getAttribute('updatehover') == 'true'); // Notiere ob es eine Hovergrafik werden soll
    } else if(this.responseClass == 'marketRes') { // Falls es sich um eine Einrichtung eines Marktplatzlinkes handelt
      var additionalParams = '';
      if(xmlDataOfReturnTag.getAttribute('addtext') != null) additionalParams += ', "' + xmlDataOfReturnTag.getAttribute('addtext') + '"';
      if(xmlDataOfReturnTag.getAttribute('sourceform') != null) additionalParams += ', "' + xmlDataOfReturnTag.getAttribute('sourceform') + '"';
      if(xmlDataOfReturnTag.getAttribute('inputtypes') != null) additionalParams += ', "' + xmlDataOfReturnTag.getAttribute('inputtypes') + '"';
      this.marketCall = new Function('return(marketResWindow("' + xmlDataOfReturnTag.getAttribute('markettext') + '", ' + xmlDataOfReturnTag.getAttribute('missingore') + ', ' + xmlDataOfReturnTag.getAttribute('missinggold') + ', ' + xmlDataOfReturnTag.getAttribute('missingwood') + ', ' + xmlDataOfReturnTag.getAttribute('missingfood') + ', ' + xmlDataOfReturnTag.getAttribute('missingsilver') + ', ' + xmlDataOfReturnTag.getAttribute('costore') + ', ' + xmlDataOfReturnTag.getAttribute('costgold') + ', ' + xmlDataOfReturnTag.getAttribute('costwood') + ', ' + xmlDataOfReturnTag.getAttribute('costfood') + ', ' + xmlDataOfReturnTag.getAttribute('costsilver') + ', "' + xmlDataOfReturnTag.getAttribute('veggie') + '", "' + xmlDataOfReturnTag.getAttribute('backlink') + '", "' + xmlDataOfReturnTag.getAttribute('backlinkname') + '"' + additionalParams + '))');
    } else if(this.responseClass == 'refresh') { // Falls es sich um eine Veränderung von bestehendem Inhalt handelt
      if(this.returnVal == 'res') {			// Bei Resaktualisierung
        this.ore = parseInt(xmlDataOfReturnTag.getAttribute('ore'), 10);
        this.gold = parseInt(xmlDataOfReturnTag.getAttribute('gold'), 10);
        this.wood = parseInt(xmlDataOfReturnTag.getAttribute('wood'), 10);
        this.food = parseInt(xmlDataOfReturnTag.getAttribute('food'), 10);
        this.silver = parseInt(xmlDataOfReturnTag.getAttribute('silver'), 10);
      }
    }

  }

  /**
    * Verarbeite XML-Daten, die von einem XMLHTTP-Request an actions.php gekommen sind
    */
  function processResponse(xmlData) {
    var returnValues = xmlData.getElementsByTagName('return');	// Hole alle Return-Values (bitte Gott, lass es nur einen sein ;)
    if(returnValues.length > 0) {			// Falls ein Rückgabe-XML-Tag gefunden wurde
      var resultList = $A();			// Erstelle neuen Array
      for(var i = 0, len = returnValues.length; i < len; ++i) {
        if(returnValues[i].getAttribute('retval') == 'false') tmpResult = false; // Falls der Rückgabewert false ist, übersetze dies nach JavaScript
        else if(returnValues[i].getAttribute('retval') == 'true') tmpResult = true; // Falls der Rückgabewert true ist, übersetze dies nach JavaScript
        else tmpResult = returnValues[i].getAttribute('retval');	// Ansonsten übernehme einfach den String, der im entsprechenden Attribut steht
        resultList.push(new responseDataObject(tmpResult, returnValues[i].getAttribute('class'), returnValues[i]));
      }
      return(resultList);				// Gebe neues Antwort-Objekt zurück, in dem die nötigen Werte stehen
    }
    return($A()); // Falls kein Rückgabe-XML-Tag gefunden wurde gebe leere Liste zurück
  }

  /**
    * Verarbeitet einen HTTP-Request, der über XHR1.send verschickt wurde so,
    * dass er allgemein nutzbar ist (NEU)
    */
  function processRequestDL4(httpReq) {
    defaultProcessing(processResponse(httpReq.responseXML));
  }

  /**
    * Verarbeitet einen HTTP-Request, der über XHR1.send verschickt wurde so,
    * dass er allgemein nutzbar ist
    */
  function processRequest(httpReq, reqStatus, reqData) {
    if (reqStatus == XHR1.OK) {						// Wenn der Status der HTTP-Antwort OK ist
	responseData = processResponse(httpReq.responseXML);			// Verarbeite XML-Daten in der Antwort
	if(reqData && xDef(reqData.fCall)) {						// Falls ein Funktionsaufruf im Userobjekt steckt
	  reqData.fCall(responseData);						// Führe Funktionsaufruf aus und übergebe Ergebnis-Objekt und User-Objekt
	}
    } else {
      s = '';
      if (reqStatus & XHR1.TIMEOUT) {
        s = '[b]Fehler durch Timeout[/b]';
      }
      if (reqStatus & XHR1.NOXMLCT) {
        s = '[b]XML-Inhalt erwartet, aber ' + httpReq.getResponseHeader('Content-Type') + ' empfangen.\n\nMöglicherweise müsst Ihr Euch neu einloggen:[/b] [url=logout.php]Logout & zum Portal[/url]';
      }
      if (reqStatus & XHR1.RSPERR) {
        s = '[b]Fehlerhafte Antwort (' + httpReq.status + '): ' + httpReq.statusText + '[/b]';
      }
      infoWindow(s, 'XMLRequestError');
    }
  }

  /**
    * Standardfunktion die als Callback für XMLHTTPRequests aufgerufen wird.
    * Gibt nur die zurückgegebene Meldung im entsprechenden Format aus
    */
  function defaultProcessing(responseData) {
    for(var i = 0, len = responseData.length; i < len; ++i) {		// Gehe alle Rückmeldungen durch
      if(responseData[i].responseClass == 'forward') {			// Falls die Antwort eine Weiterleitung ist
        location.href = responseData[i].fwdUrl;					// Führe Weiterleitung durch
      } else if(responseData[i].responseClass == 'ask') {			// Falls die Antwort eine Frage mit Weiterleitung ist
        createQuestionWindow(responseData[i]);				// Erstelle ein entsprechendes Frage-Fenster
      } else if(responseData[i].responseClass == 'refresh') {		// Falls die Antwort eine Aktualisierung der Queue ist
      	if(responseData[i].returnVal == 'queue') {
      	  refreshQueue();							// Aktualisiere die Queue
      	} else if(responseData[i].returnVal == 'res') {
      	  refreshRes(responseData[i]);						// Aktualisiere Resanzeige
      	}
      } else if(responseData[i].responseClass == 'rewrite') {		// Falls ein Element verändert werden soll
      	//layerWrite(responseData[i].returnVal, responseData[i].message.replace(/\n/g, '<br />'));
    	deleteContent(responseData[i].returnVal);
    	addBBCode(responseData[i].returnVal, responseData[i].message, true);
      	$(responseData[i].returnVal).className = responseData[i].newClass;
      } else if(responseData[i].responseClass == 'chgfx') {		// Falls ein Bildelement verändert werden soll
      	$(responseData[i].returnVal).src = responseData[i].newSrc;		// Ändere die Bildquelle wie gewünscht
      	if(responseData[i].updateHover) enableHoverImageDL($(responseData[i].returnVal));			// Aktualisiere Hoversystem falls nötig
      } else if(responseData[i].responseClass == 'marketRes') {		// Falls ein Marktlink werden soll
      	Event.stopObserving(responseData[i].returnVal, 'click');			// Lösche alle bestehenden Klick-Handler, denn hier kommt nun ein Neuling
      	$(responseData[i].returnVal).onclick = null;					// Auch diese hier müssen weg. Scheiss obtrusive JS :/
      	Event.observe(responseData[i].returnVal, 'click', responseData[i].marketCall); // Füge das neue Klickevent hinzu
      } else {
        infoWindow('[span=' + responseData[i].responseClass + ']' + responseData[i].message + '[/span]', 'defaultAnswerWindow'); // Gebe Meldung aus
      }
    }
  }
  
  /**
    * Aktualisiert per AJAX-Request die Queue von DL4
    */
  function refreshQueue() {
    new Ajax.Updater('dl4QueueContent', 'actions.php', { method: 'get', parameters: {'location': 'queue'}, onComplete: getEndzeit});
    return(true);
  }

  /**
    * Aktualisiert per AJAX-Request die Resanzeige von DL4
    */
  function refreshRes(resData) {
    $('user_erz').innerHTML = I18N.numberFormat(resData.ore, 0);
    $('user_gold').innerHTML = I18N.numberFormat(resData.gold, 0);
    $('user_holz').innerHTML = I18N.numberFormat(resData.wood, 0);
    $('user_nahrung').innerHTML = I18N.numberFormat(resData.food, 0);
    $('user_silber').innerHTML = I18N.numberFormat(resData.silver, 0);
    return(true);
  }


  /**
    * Versucht ein übergebenes Formular über einen XMLHTTP-Request zu verschicken, sofern möglich.
    * Ist es nicht möglich, gibt die Funktion true zurück und das Formular wird ganz normal submittet.
    * Sollte immer im onsubmit eines form-Elements stehen.
    */
  function tryToSendAsXMLHTTP(formElem) {
    if(formElem.nodeName == 'FORM') {			// Falls wir überhaupt ein Formular übergeben bekommen haben
      if(XHR1.status != XHR1.NOXMLOBJ) {			// Falls asynchrone Requests erlaubt werden
        if(!XHR1.busy) {							// Falls das Request-Objekt noch arbeitet
      	  var curDate = new Date();
      	  var sendAsPost = formElem.getAttribute('method').toLowerCase() == 'post'; // Prüfe als was das Formular übermittelt wird
      	  var formUrl = (formElem.getAttribute('action').charAt(0) == '?' ? 'actions.php' + formElem.getAttribute('action') : formElem.getAttribute('action').substr(0, 7) == 'http://' ? formElem.getAttribute('action').replace('main.php', 'actions.php') : formElem.getAttribute('action'))

      	  var userObj = { fCall: defaultProcessing };
          if(XHR1.send((sendAsPost ? 'POST' : 'GET'), formUrl, Form.serialize(formElem, { submit: false, hash: false }) + '&curtime=' + curDate.getTime(), 15000, false, true, userObj, processRequest)) {
      	    return(false);
      	  }
      	}
      }
    }
    return(true);					// Wenn wir bis hierher gekommen sind, geben wir true zurück und der Browser schickt das Formular über den altgediegenen Weg ab
  }

  /**
    * Klasse für Scrolling im
    */
  var Scrolling = {

    initialized: false,					// Variable die angibt, ob das Scrolling bereits initialisiert ist

    maxLeft: 175,					//  Bereite
    maxTop: 155,					//	Scrollgrenzen
    minLeft: 170,					//		vor
    minTop: 270,					//

    curLeft: 0,						// Aktuelle X-Position der Siedlung
    curTop: 0,						// Aktuelle Y-Position der Siedlung

    areaWidth: 1754,					// Breite der Siedlung (+ 2 Px Rand links und rechts)
    areaHeight: 1304,					// Höhe der Siedlung (+ 2 Px Rand oben und unten)

    areaScroll: function(elem, dx, dy, eventObj) {	// Scrolle um eine bestimmte Entfernung
      var dl4Area = $('dl4Area');				// Hole Siedlung
      Scrolling.curLeft = xLeft(dl4Area, Math.max(Math.min(Scrolling.curLeft + dx, Scrolling.maxLeft), -Scrolling.areaWidth - Scrolling.minLeft + xClientWidth()));
      Scrolling.curTop = xTop(dl4Area, Math.max(Math.min(Scrolling.curTop + dy, Scrolling.maxTop), -Scrolling.areaHeight - Scrolling.minTop + xClientHeight()));
      xWidth(dl4Area, Math.min(Scrolling.areaWidth, -Scrolling.curLeft + xClientWidth()));
      xHeight(dl4Area, Math.min(Scrolling.areaHeight, -Scrolling.curTop + xClientHeight()));
    },

    prepare: function(doDrag) {				// Funktion zum Vorbreiten von Scrolling
      var dl4Area = $('dl4Area');					// Hole Siedlung
      Scrolling.curLeft = xLeft(dl4Area);				// Setze aktuellen links-Wert
      Scrolling.curTop = xTop(dl4Area);				// Setze aktuellen oben-Wert
      xWidth(dl4Area, Math.min(Scrolling.areaWidth, -Scrolling.curLeft + xClientWidth())); // Setze aktuelle Größe
      xHeight(dl4Area, Math.min(Scrolling.areaHeight, -Scrolling.curTop + xClientHeight())); // Setze aktuelle Größe
      if(!Scrolling.initialized && doDrag == true) {			// Falls Scrolling noch nicht initialisiert ist
      	Scrolling.initialized = true;					// Setze auf es auf initialisiert
        xStyle('cursor', 'move', dl4Area);				// Setze Cursor
        xEnableDrag('dl4Area', null, Scrolling.areaScroll, Scrolling.saveScrollingPosition);
      }
    },
    
    saveScrollingPosition: function() {
      savePosition(5, Scrolling.curLeft - xScrollLeft(), Scrolling.curTop - xScrollTop(), Math.min(Scrolling.areaWidth, -Scrolling.curLeft + xClientWidth()), Math.min(Scrolling.areaHeight, -Scrolling.curTop + xClientHeight()));    	
    }
  }

  var Buildings = {
  
    bPlacer: false,	// Variable die das Element enthält, welches platziert werden soll	
    bPlacerOffsetX: false,
    bPlacerOffsetY: false,
    
    showHardSpaces : function(container) {
    	var objectSpaces = $(container).getElementsByClassName('dl4Objspace');
	for(var i = 0, len = objectSpaces.length; i < len; ++i) {
      		objectSpaces[i].style.display = 'block';
      	}
    },
  
    /**
      * Ermögliche das Platzieren eines Gebäudes
      * @params
      * bid ist die ID des Gebäudes das platziert wird
      * bFeldname ist der Teil des Namens des DIVs, in dem das Gebäude steckt
      * bImgId die ID des Objekts, an dem die erstmalige Platzierung erfolgt (danach folgt das Objekt dem Cursor
      * autobuy enthält die Priorität der zu verkaufenden Ressourcen, wenn das automatische Marktplatzverwenden aktiviert wird
      */
    enablePlacement: function(bid, bFeldname, bImgId, autobuy, decoration, decorationCategory) {
      var bIcon = $(bImgId);
      var isDecoration = false;
      Buildings.bPlacer = $('dl4' + bFeldname + '_').addClassName('dl4Placer'); // Zeige Gebäudeplatzierungsobjekt und speichere es in einer Variable
      Buildings.bPlacer.style.display = 'block';
      Buildings.bPlacerOffsetX = Math.floor(- xWidth(Buildings.bPlacer) / 2);
      Buildings.bPlacerOffsetY = Math.floor(- xHeight(Buildings.bPlacer) / 2);

      if($('dl4HighlightBig')) $('dl4HighlightBig').hide(); // Hide tutorial highlight if necessary
      
      var abortBuild = infoWindow(I18N.getSpecificString('BUILDING_PLACEMENT_INFO'), 'abortPlacement');
      xCenter(abortBuild);
      xTop(abortBuild, 0);
      if(decorationCategory != undefined) { // If there is a decoration category defined
      	if(decoration !== true && decoration > 0) isDecoration = true; // It is a true decoration if it has a decoration id. If a building is placed through the settleshop, then it has no decoration id.
      	Scrolling.prepare(true);			// Breite Scrolling vor, wenn nicht schon geschehen
      	Event.observe($('abortPlacementClose').firstChild, 'click', function() { justRelocation('?location=settleshop~category=' + String(decorationCategory)); }); // We return to the settle shop on abort
      } else {					// Otherwise, if this is not a decoration
        Event.observe($('abortPlacementClose').firstChild, 'click', function() { location.href = '?location=bauten' + (location.href.indexOf('sub=RG') != -1 ? '&sub=RG' : ''); }); // We return to the building menu on abort
      }
      var bPlaceArea = document.createElement('div');
      bPlaceArea.id = 'dl4BuildingPlace';
      bPlaceArea.appendChild(Buildings.bPlacer);
      xHeight(bPlaceArea, xClientHeight());
      $(mainObjectId).appendChild(bPlaceArea);

      Buildings.showHardSpaces('dl4Area');
      Buildings.showHardSpaces(Buildings.bPlacer);

      if(is_ie6) {
        xLeft(bPlaceArea, 0); xTop(bPlaceArea, 0);
        xStyle('width', '100%', bPlaceArea);
        xStyle('zIndex', '10049', bPlaceArea);
      }
      
      var def = $('dl4Verteidigung_');
      if(isDecoration || (bid != 5 && xGetComputedStyle(def, 'display') == 'none')) {
        xResizeTo(def, 300, 228);
        xMoveTo(def, 0, 1072);
        xStyle('zIndex', '10060', def);
        xStyle('backgroundImage', 'url("' + useGrafikpfad + '/gebaeude/verteidigung_placer.gif")', def);
        xStyle('display', 'block', def);
      }


      xLeft(Buildings.bPlacer, xPageX(bIcon));
      xTop(Buildings.bPlacer, xPageY(bIcon));
      xHide('dl4MainMenu'); xHide('dl4Queue'); xHide('dl4TopArea'); xHide('dl4MainContent'); xHide('dl4Maximizer');
      Event.observe('dl4BuildingPlace', 'mousemove', function(curEvent) { Buildings.moveBuilding(curEvent); });
      if(isDecoration) {
      	Buildings.startBuilding = function(curElem, curEventPageX, curEventPageY, curEvent, distanceX, distanceY) { if(distanceX < 5 && distanceY < 5) Buildings.placeDecoration(curEvent, decoration, decorationCategory, autobuy); else Scrolling.saveScrollingPosition(); };
      } else {
        Buildings.startBuilding = function(curElem, curEventPageX, curEventPageY, curEvent, distanceX, distanceY) { if(distanceX < 5 && distanceY < 5) Buildings.placeBuilding(curEvent, bid, autobuy, decoration); else Scrolling.saveScrollingPosition(); };
      }
      //Event.observe('dl4BuildingPlace', 'click', Buildings.startBuilding);
      xEnableDrag('dl4BuildingPlace', null, Scrolling.areaScroll, Buildings.startBuilding);

    },

    /**
      * Platziere Gebäude bei Klick in die entsprechende Gegend
      */
    placeBuilding: function(curEvent, bid, autobuy, decorational) {
      //Event.stopObserving('dl4BuildingPlace', 'click', Buildings.startBuilding);
      justRelocation('?location=bauten' + (bid >= 10 && bid <= 15 ? '~sub=RG' : '') + '~build=' + String(bid) + '~x=' + (curEvent.pageX - Scrolling.curLeft + Buildings.bPlacerOffsetX) + '~y=' + (curEvent.pageY - Scrolling.curTop + Buildings.bPlacerOffsetY) + (autobuy != -1 ? '~autobuy=true~sellPriority=' + String(autobuy) : '') + (decorational != undefined && decorational != false ? '~decorational=yes' : ''));
    },
    
    /**
      * Platziere Gebäude bei Klick in die entsprechende Gegend
      */
    placeDecoration: function(curEvent, decorationId, decorationCategory, payMethod) {
      //Event.stopObserving('dl4BuildingPlace', 'click', Buildings.startBuilding);
      justRelocation('?location=settleshop~category=' + String(decorationCategory) + '~payMethod=' + payMethod + '~place=' + String(decorationId) + '~x=' + (curEvent.pageX - Scrolling.curLeft + Buildings.bPlacerOffsetX) + '~y=' + (curEvent.pageY - Scrolling.curTop + Buildings.bPlacerOffsetY));
    },
    
    /**
      * Starte einen Gebäudebau bei ganz normalem Ausbau
      */
    startBuild: function(bid, subType) {
      if(subType == 'RG') {
        new Ajax.Request('actions.php', {
      	  method: 'get',
      	  parameters: {
      			'location': 'buildings',
      			'build': bid,
      			'sub': subType
			},
      	  onSuccess: processRequestDL4,
      	  onFailure: function() {
      		justRelocation('?location=bauten~build='  + bid + '~sub=' + subType);
      		}
        });
        return(false);
      } else {
        return(justRelocation('?location=bauten~build='  + bid + '~sub=' + subType));
      }
    },
    
    /**
      * Bewegt das aktive Gebäude entlang des Zeigers auf der Karte
      */
    moveBuilding: function(curEvent) {
      xLeft(Buildings.bPlacer, curEvent.pageX + Buildings.bPlacerOffsetX);
      xTop(Buildings.bPlacer, curEvent.pageY + Buildings.bPlacerOffsetY);
    }

  }

  /**
    * Bewegt das Eierfenster an die entsprechende Position
    */
  function moveEggs() {
    var dl4Eggs = $('dl4Eggs');			// Hole bisheriges Eierfenster
    if(dl4Eggs) {				// Falls das Fenster existiert
      enableDragWithHelper('dl4EggMover', 'dl4Eggs', null, function() { var eggs = $('dl4Eggs'); eggs.basicX = xLeft(eggs); eggs.basicY = xTop(eggs); }); // Ermögliche das Ziehen des Eierfensters
      xLeft(dl4Eggs, 150); // Bewege das Eierfenster links oder rechts daneben, je nach Position
      xTop(dl4Eggs, 150);			// Bewege das Eierfenster auf die selbe Höhe
      xShow(dl4Eggs);					// Zeige es an
    }
  }
  
  /**
    * Geht alle TRs durch und markiert invertiert die folgende Auswahl
    */
  function markEveryLineAfter(trId) {
    var curTr = $(trId);			// Hole das Startelement
    while(curTr != undefined) {			// Solange ein Element existiert
      if(curTr.nodeName == 'TR') {		// Prüfe ob es eine Zeile ist
        var inputList = curTr.getElementsByTagName('input'); // Hole alle Eingabeelemente innerhalb der Zeile
        for(var i = 0, len = inputList.length; i < len; ++i) {	// Gehe alle Inputs durch
          if(inputList[i].type == 'checkbox') inputList[i].checked = !inputList[i].checked; // Falls es eine Checkbox ist, invertiere die Auswahl
        }
      }
      curTr = curTr.next();			// Hole Nachbarelement (nächste Zeile, wenn alles gut läuft)
    }
  }
  
  /**
    * Speichert per AJAX die Truppendaten
    */ 
  function saveTroopSettings() {
    tryToSendAsXMLHTTP($('mission'));
    return(false);
  }

/**
  * Function to show a highlight pointer next to an element. The type of pointer as well as its position can be configured by parameters
  */
function highlightArea(highlight, highlightType, highlightPosition, withMouseOverCallback, withClickCallback) {
    highlight = $(highlight);
    var highlightNode = $('dl4Highlight' + highlightType);
    if(!highlightNode) {
      highlightNode = Element.extend(document.createElement("div"));
      highlightNode.id = 'dl4Highlight' + highlightType;
      $(mainObjectId).appendChild(highlightNode);
    } else if(typeof(highlightNode.curListener) != 'undefined' && highlightNode.curListener != null) { // If we have a highlight node and it has an old listener, we must remove it
      Event.stopObserving(highlightNode.curListener, 'mouseover', highlightNode.curMouseOverHandler);
      Event.stopObserving(highlightNode.curListener, 'mouseout', highlightNode.curMouseOutHandler);
      Event.stopObserving(highlightNode.curListener, 'click', highlightNode.curClickHandler);
      highlightNode.curListener = null;				// Delete the listener so we will not try to stop observing it again (if we don't add a new listener)
    }
    highlightNode.className = 'highlight' + highlightType + highlightPosition + 'Unvisited';
    highlightNode.show();					// Show the highlight indicator
    if(highlightPosition == 'Down') {
      var moveToX = xPageX(highlight) - (xWidth(highlightNode) - xWidth(highlight)) / 2.0;
      var moveToY = xPageY(highlight) - xHeight(highlightNode);
    } else if(highlightPosition == 'Up') {
      var moveToX = xPageX(highlight) - (xWidth(highlightNode) - xWidth(highlight)) / 2.0;
      var moveToY = xPageY(highlight) + xHeight(highlight);
    } else if(highlightPosition == 'Right') {
      var moveToX = xPageX(highlight) - xWidth(highlightNode);
      var moveToY = xPageY(highlight) - (xHeight(highlightNode) - xHeight(highlight)) / 2.0;
    } else if(highlightPosition == 'Left') {
      var moveToX = xPageX(highlight) + xWidth(highlight);
      var moveToY = xPageY(highlight) - (xHeight(highlightNode) - xHeight(highlight)) / 2.0;
    }
    xMoveTo(highlightNode, moveToX, moveToY);			// Move to highlight indicator to the calculated position
    if(withMouseOverCallback) {					// If we should react to mouseovers on the highlighted object
      highlightNode.curListener = highlight;				// Store the highlight listener, so that we can remove him later on, if needed
      highlightNode.curMouseOverHandler = function(e) { highlightNode.removeClassName('highlight' + highlightType + highlightPosition + 'Unvisited').addClassName('highlight' + highlightType + highlightPosition + 'Visited'); }; // Store the mouseover handler that will mark the highlight
      highlightNode.curMouseOutHandler = function(e) { highlightNode.removeClassName('highlight' + highlightType + highlightPosition + 'Visited').addClassName('highlight' + highlightType + highlightPosition + 'Unvisited'); } // Store the mouseout handler that will unmark the highlight
      highlightNode.curClickHandler = function(e) { highlightNode.hide(); highlightNode.removeClassName('highlight' + highlightType + highlightPosition + 'Visited').addClassName('highlight' + highlightType + highlightPosition + 'Unvisited'); }; // Store the click handler that will hide the highlight on clicking
      Event.observe(highlight, 'mouseover', highlightNode.curMouseOverHandler); // Observe mouseover
      Event.observe(highlight, 'mouseout', highlightNode.curMouseOutHandler); // and mouseout on highlight object to change the highlight indicator accordingly
      if(withClickCallback) {						// If the indicator shall disappear after clicking the highlighted object
      	Event.observe(highlight, 'click', highlightNode.curClickHandler); // We also register the onclick handler
      }
    }
    return(true);
}

function showTavernTable(tableId, chairId) {

  var idArr = new Array(1);				// Create new array for the creation of specific strings
  idArr[0] = tableId;					// Add the table ID as first and only element of the array
  deleteContent("tavernTableHeading");			// Delete table info heading
  addBBCode("tavernTableHeading", I18N.getSpecificString("tavernTableWithId", idArr), true); // Update the heading to contain the table and its id

  deleteContent("tavernTableInfo");			// Delete table info area
  if(typeof(tableData[tableId]) != "undefined") {	// If a table with the given ID is defined
    bbCodeResult = "";						// Create a BB code variable
    for(var i = 0, len = tableData[tableId].length; i < len; ++i) { // Go through all elements of the table
      if(typeof(tableData[tableId][i]) != "undefined") {		// If there is a chair at the current position
        if(chairId == (i + 1)) bbCodeResult += "[b][color=tomato][span=smallinfo]" + tableData[tableId][i][2] + "[/span] " + tableData[tableId][i][1] + "[/color][/b]\n"; // Store the highlighted name, if this is the chair we are looking for
        else bbCodeResult += "[span=smallinfo]" + tableData[tableId][i][2] + "[/span] " + tableData[tableId][i][1] + "\n"; // Otherwise just store the name
      }
    }
    addBBCode("tavernTableInfo", bbCodeResult, true);		// Add the BB code to the table info area
  } else {						// If no such table exists
    addBBCode("tavernTableInfo", I18N.getSpecificString("tavernTableEmpty", idArr), true); // Notify the user that the table is empty
  }
  return(true);
}

/** Prototype Extensions
  */
  
Object.extend(Date.prototype, {
  strftime: function(format) {
    var day = this.getUTCDay(), month = this.getUTCMonth();
    var hours = this.getUTCHours(), minutes = this.getUTCMinutes();
    function pad(num) { return num.toPaddedString(2); };

    return format.gsub(/\%([aAbBcdDHiImMpSwyY])/, function(part) {
      switch(part[1]) {
        case 'a': return $w("Sun Mon Tue Wed Thu Fri Sat")[day]; break;
        case 'A': return $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday")[day]; break;
        case 'b': return $w("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")[month]; break;
        case 'B': return $w("January February March April May June July August September October November December")[month]; break;
        case 'c': return this.toString(); break;
        case 'd': return this.getUTCDate(); break;
        case 'D': return pad(this.getUTCDate()); break;
        case 'H': return pad(hours); break;
        case 'i': return (hours === 12 || hours === 0) ? 12 : (hours + 12) % 12; break;
        case 'I': return pad((hours === 12 || hours === 0) ? 12 : (hours + 12) % 12); break;
        case 'm': return pad(month + 1); break;
        case 'M': return pad(minutes); break;
        case 'p': return hours > 11 ? 'PM' : 'AM'; break;
        case 'S': return pad(this.getUTCSeconds()); break;
        case 'w': return day; break;
        case 'y': return pad(this.getUTCFullYear() % 100); break;
        case 'Y': return this.getUTCFullYear().toString(); break;
      }
    }.bind(this));
  }
});