[Orxonox-commit 1945] r6662 - in code/branches/gamestates2: . data/gui/scripts data/lua src/libraries/core src/libraries/core/input src/libraries/util

rgrieder at orxonox.net rgrieder at orxonox.net
Wed Mar 31 01:05:29 CEST 2010


Author: rgrieder
Date: 2010-03-31 01:05:28 +0200 (Wed, 31 Mar 2010)
New Revision: 6662

Added:
   code/branches/gamestates2/data/lua/Debugger.lua
   code/branches/gamestates2/data/lua/Strict.lua
Modified:
   code/branches/gamestates2/
   code/branches/gamestates2/data/gui/scripts/AudioMenu.lua
   code/branches/gamestates2/data/gui/scripts/BasicGUI.lua
   code/branches/gamestates2/data/gui/scripts/ControlsMenu.lua
   code/branches/gamestates2/data/gui/scripts/CreditsMenu.lua
   code/branches/gamestates2/data/gui/scripts/DecisionPopup.lua
   code/branches/gamestates2/data/gui/scripts/GUITools.lua
   code/branches/gamestates2/data/gui/scripts/GameplayMenu.lua
   code/branches/gamestates2/data/gui/scripts/GraphicsMenu.lua
   code/branches/gamestates2/data/gui/scripts/InGameMenu.lua
   code/branches/gamestates2/data/gui/scripts/InfoPopup.lua
   code/branches/gamestates2/data/gui/scripts/InitialiseGUI.lua
   code/branches/gamestates2/data/gui/scripts/KeyBindMenu.lua
   code/branches/gamestates2/data/gui/scripts/MainMenu.lua
   code/branches/gamestates2/data/gui/scripts/MouseControlsMenu.lua
   code/branches/gamestates2/data/gui/scripts/MultiplayerMenu.lua
   code/branches/gamestates2/data/gui/scripts/MultiplayerOptionsMenu.lua
   code/branches/gamestates2/data/gui/scripts/PickupInventory.lua
   code/branches/gamestates2/data/gui/scripts/QuestGUI.lua
   code/branches/gamestates2/data/gui/scripts/SettingsMenu.lua
   code/branches/gamestates2/data/gui/scripts/SingleplayerMenu.lua
   code/branches/gamestates2/data/lua/LuaStateInit.lua
   code/branches/gamestates2/src/libraries/core/Core.cc
   code/branches/gamestates2/src/libraries/core/Core.h
   code/branches/gamestates2/src/libraries/core/GUIManager.cc
   code/branches/gamestates2/src/libraries/core/GUIManager.h
   code/branches/gamestates2/src/libraries/core/LuaState.cc
   code/branches/gamestates2/src/libraries/core/LuaState.h
   code/branches/gamestates2/src/libraries/core/Resource.cc
   code/branches/gamestates2/src/libraries/core/Resource.h
   code/branches/gamestates2/src/libraries/core/input/InputDevice.h
   code/branches/gamestates2/src/libraries/core/input/InputHandler.h
   code/branches/gamestates2/src/libraries/core/input/InputManager.cc
   code/branches/gamestates2/src/libraries/core/input/InputManager.h
   code/branches/gamestates2/src/libraries/core/input/InputPrereqs.h
   code/branches/gamestates2/src/libraries/core/input/InputState.h
   code/branches/gamestates2/src/libraries/util/Singleton.h
Log:
Merged revisions 6621-6661 to gamestates2.


Property changes on: code/branches/gamestates2
___________________________________________________________________
Modified: svn:mergeinfo
   - /code/branches/buildsystem:1874-2276,2278-2400
/code/branches/buildsystem2:2506-2658
/code/branches/buildsystem3:2662-2708
/code/branches/ceguilua:1802-1808
/code/branches/console:5941-6104
/code/branches/core3:1572-1739
/code/branches/core4:3221-3224,3227,3234-3238,3242,3244-3250,3252-3254,3256,3259-3261,3264-3265,3268-3275,3277-3278,3280,3284-3285,3287,3289-3294,3305,3309-3310
/code/branches/core5:5768-5928,6009
/code/branches/gamestate:6430-6572
/code/branches/gametypes:2826-3031
/code/branches/gcc43:1580
/code/branches/gui:1635-1723,2795-2894
/code/branches/ingamemenu:6000-6023
/code/branches/input:1629-1636
/code/branches/libraries:5612-5692
/code/branches/libraries2:5703-5737
/code/branches/lodfinal:2372-2411
/code/branches/map:2801-3086,3089
/code/branches/menu:5941-6146,6148
/code/branches/miniprojects:2754-2824
/code/branches/netp2:2835-2988
/code/branches/netp3:2988-3082
/code/branches/netp6:3214-3302
/code/branches/network:2356
/code/branches/network64:2210-2355
/code/branches/objecthierarchy:1911-2085,2100,2110-2169
/code/branches/objecthierarchy2:2171-2479
/code/branches/overlay:2117-2385
/code/branches/particles:2829-3085
/code/branches/particles2:6050-6106,6109
/code/branches/pch:3113-3194
/code/branches/physics:1912-2055,2107-2439
/code/branches/physics_merge:2436-2457
/code/branches/pickup2:5942-6405
/code/branches/pickup3:6418-6523
/code/branches/pickups:1926-2086,2127,2827-2915
/code/branches/pickups2:2107-2497,2915-3071
/code/branches/presentation:2369-2652,2654-2660
/code/branches/presentation2:6106-6416
/code/branches/questsystem:1894-2088
/code/branches/questsystem2:2107-2259
/code/branches/questsystem5:2776-2905
/code/branches/resource:3327-3366
/code/branches/resource2:3372-5694
/code/branches/script_trigger:1295-1953,1955
/code/branches/sound:2829-3010
/code/branches/sound3:5941-6102
/code/branches/steering:5949-6091
/code/branches/weapon:1925-2094
/code/branches/weapon2:2107-2488
/code/branches/weapons:2897-3051
/code/branches/weaponsystem:2742-2890
   + /code/branches/buildsystem:1874-2276,2278-2400
/code/branches/buildsystem2:2506-2658
/code/branches/buildsystem3:2662-2708
/code/branches/ceguilua:1802-1808
/code/branches/console:5941-6104
/code/branches/core3:1572-1739
/code/branches/core4:3221-3224,3227,3234-3238,3242,3244-3250,3252-3254,3256,3259-3261,3264-3265,3268-3275,3277-3278,3280,3284-3285,3287,3289-3294,3305,3309-3310
/code/branches/core5:5768-5928,6009
/code/branches/gamestate:6430-6572,6621-6661
/code/branches/gametypes:2826-3031
/code/branches/gcc43:1580
/code/branches/gui:1635-1723,2795-2894
/code/branches/ingamemenu:6000-6023
/code/branches/input:1629-1636
/code/branches/libraries:5612-5692
/code/branches/libraries2:5703-5737
/code/branches/lodfinal:2372-2411
/code/branches/map:2801-3086,3089
/code/branches/menu:5941-6146,6148
/code/branches/miniprojects:2754-2824
/code/branches/netp2:2835-2988
/code/branches/netp3:2988-3082
/code/branches/netp6:3214-3302
/code/branches/network:2356
/code/branches/network64:2210-2355
/code/branches/objecthierarchy:1911-2085,2100,2110-2169
/code/branches/objecthierarchy2:2171-2479
/code/branches/overlay:2117-2385
/code/branches/particles:2829-3085
/code/branches/particles2:6050-6106,6109
/code/branches/pch:3113-3194
/code/branches/physics:1912-2055,2107-2439
/code/branches/physics_merge:2436-2457
/code/branches/pickup2:5942-6405
/code/branches/pickup3:6418-6523
/code/branches/pickups:1926-2086,2127,2827-2915
/code/branches/pickups2:2107-2497,2915-3071
/code/branches/presentation:2369-2652,2654-2660
/code/branches/presentation2:6106-6416
/code/branches/questsystem:1894-2088
/code/branches/questsystem2:2107-2259
/code/branches/questsystem5:2776-2905
/code/branches/resource:3327-3366
/code/branches/resource2:3372-5694
/code/branches/script_trigger:1295-1953,1955
/code/branches/sound:2829-3010
/code/branches/sound3:5941-6102
/code/branches/steering:5949-6091
/code/branches/weapon:1925-2094
/code/branches/weapon2:2107-2488
/code/branches/weapons:2897-3051
/code/branches/weaponsystem:2742-2890

Modified: code/branches/gamestates2/data/gui/scripts/AudioMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/AudioMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/AudioMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- AudioMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("AudioMenu")
-if _REQUIREDNAME == nil then
-    AudioMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("AudioMenu")
 
-function P:init()
+function P.init()
     soundMgr = orxonox.SoundManager:getInstance()
     block = false
     masterscrollbar_active = false

Modified: code/branches/gamestates2/data/gui/scripts/BasicGUI.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/BasicGUI.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/BasicGUI.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,11 +1,7 @@
--- gui.lua
+-- BasicGUI.lua
 
 local P = {}
-if _REQUIREDNAME == nil then
-    BasicGUI = P
-else
-    _G[_REQUIREDNAME] = P
-end
+_G[_REQUIREDNAME or "BasicGUI"] = P
 
 -- useless, even wrong? P is the class, not the object..
 P.overlay = nil
@@ -26,7 +22,8 @@
 function P:init()
 end
 
--- Override this function if you need to
+-- Override this function if you want to change one of the three input parameters:
+-- showCursor = true, useKeyboard = true and blockJoyStick = false
 -- But don't forget to stick to the naming convention ("GUI_" .. self.filename)
 function P:createInputState()
     self.inputState = guiMgr:createInputState("GUI_" .. self.filename)

Modified: code/branches/gamestates2/data/gui/scripts/ControlsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/ControlsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/ControlsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- ControlsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("ControlsMenu")
-if _REQUIREDNAME == nil then
-    ControlsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("ControlsMenu")
 
 function P.ControlsMouseControlsButton_clicked(e)
     showGUI("MouseControlsMenu", true)

Modified: code/branches/gamestates2/data/gui/scripts/CreditsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/CreditsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/CreditsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,9 @@
 -- CreditsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("CreditsMenu")
-if _REQUIREDNAME == nil then
-    CreditsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local sheetName = _REQUIREDNAME or "CreditsMenu"
+-- Create object of type BasicGUI and make it global
+local P = require("BasicGUI"):new(sheetName)
+_G[sheetName] = P
 
 function P.CreditsBackButton_clicked(e)
     hideGUI(P.filename)

Modified: code/branches/gamestates2/data/gui/scripts/DecisionPopup.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/DecisionPopup.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/DecisionPopup.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- DecisionPopup.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("DecisionPopup")
-if _REQUIREDNAME == nil then
-    DecisionPopup = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("DecisionPopup")
 
 function P.setCallback(functionPtr)
     P.functionPtr = functionPtr

Modified: code/branches/gamestates2/data/gui/scripts/GUITools.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/GUITools.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/GUITools.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,3 +1,10 @@
+function createSheet(sheetName)
+    -- Create object of type BasicGUI and make it global
+    local sheet = require("BasicGUI"):new(sheetName)
+    _G[sheetName] = sheet
+    return sheet
+end
+
 function openDecisionPopup( text, callbackPtr )
     showGUI("DecisionPopup", false, true)
     DecisionPopup.setCallback(callbackPtr)

Modified: code/branches/gamestates2/data/gui/scripts/GameplayMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/GameplayMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/GameplayMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- GameplayMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("GameplayMenu")
-if _REQUIREDNAME == nil then
-    GameplayMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("GameplayMenu")
 
-function P:init()
+function P.init()
     dropdown = winMgr:getWindow("orxonox/ThemeCombobox")
     local themeList = {}
     table.insert(themeList, "Theme 1")
@@ -23,22 +17,22 @@
 
 function P.GameplayThemeCombobox_changed(e)
     -- theme
-    debug("event: theme")
+    logMessage(0, "event: theme")
 end
 
 function P.GameplayDifficultyEasyButton_clicked(e)
     -- difficulty easy
-    debug("event: easy")
+    logMessage(0, "event: easy")
 end
 
 function P.GameplayDifficultyNormalButton_clicked(e)
     -- difficulty normal
-    debug("event: normal")
+    logMessage(0, "event: normal")
 end
 
 function P.GameplayDifficultyHardButton_clicked(e)
     -- difficulty hard
-    debug("event: hard")
+    logMessage(0, "event: hard")
 end
 
 function P.GameplayBackButton_clicked(e)

Modified: code/branches/gamestates2/data/gui/scripts/GraphicsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/GraphicsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/GraphicsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- GraphicsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("GraphicsMenu")
-if _REQUIREDNAME == nil then
-    GraphicsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("GraphicsMenu")
 
-function P:init()
+function P.init()
     block = true
     file = orxonox.PathConfig:getConfigPathString() .. orxonox.getConfig("GraphicsManager", "ogreConfigFile_")
     search_mode = 0
@@ -148,7 +142,7 @@
 function P.GraphicsBrightnessScrollbar_changed(e)
     if scrollbar_active == false then
         -- brightness
-        debug("event: brightness")
+        logMessage(0, "event: brightness")
     end
 end
 
@@ -158,7 +152,7 @@
 
 function P.GraphicsBrightnessScrollbar_ended(e)
     -- brightness
-    debug("event: brightness")
+    logMessage(0, "event: brightness")
     scrollbar_active = false
 end
 

Modified: code/branches/gamestates2/data/gui/scripts/InGameMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/InGameMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/InGameMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- InGameMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("InGameMenu")
-if _REQUIREDNAME == nil then
-    InGameMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("InGameMenu")
 
 -- events for ingamemenu
 function P.button_quit_clicked(e)

Modified: code/branches/gamestates2/data/gui/scripts/InfoPopup.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/InfoPopup.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/InfoPopup.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,7 @@
 -- InfoPopup.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("InfoPopup")
+local P = createSheet("InfoPopup")
 
-if _REQUIREDNAME == nil then
-    InfoPopup = P
-else
-    _G[_REQUIREDNAME] = P
-end
-
 function P.execute(functionPtr, arguments)
     if functionPtr ~= nil then
         if arguments ~= nil then

Modified: code/branches/gamestates2/data/gui/scripts/InitialiseGUI.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/InitialiseGUI.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/InitialiseGUI.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -28,185 +28,218 @@
 system:setDefaultFont("BlueHighway-12")
 system:setDefaultTooltip("MenuWidgets/Tooltip")
 
-loadedGUIs = {}
-cursorVisibility = {}
-activeSheets = {}
-nrOfActiveSheets = 0
-root = nil
-bShowsCursor = false
-bHidePrevious = {}
+local loadedSheets = {}
+local activeMenuSheets = {size = 0, topSheet = nil}
+--activeHUDSheets  = {size = 0, topSheet = nil}
+local root = nil
 
 -- Require all tools
 require("GUITools")
 
--- loads the GUI with the specified filename
--- be sure to set the global variable "filename" before calling this function
-function loadGUI(filename)
-    -- check if it already exists
-    loadedGui = loadedGUIs[filename]
-    if loadedGui == nil then
-        loadedGuiNS = require(filename)
-        if loadedGuiNS == nil then
+
+-----------------------
+--- Local functions ---
+-----------------------
+
+-- Loads the GUI with the specified name
+-- The name corresponds to the filename of the *.lua and *.layout files
+-- but without the extension
+local function loadSheet(name)
+    -- Check if it has already been loaded
+    local sheet = loadedSheets[name]
+    if sheet == nil then
+        -- Load the sheet
+        sheet = require(name)
+        if sheet == nil then
             return
         end
-        loadedGui = loadedGuiNS:load()
-        loadedGUIs[filename] = loadedGui
-        -- if there has no GUI been loaded yet, set new GUI as current
-        if table.getn(loadedGUIs) == 1 then
-            current = loadedGUIs[1]
+        sheet:load()
+        loadedSheets[name] = sheet
+        -- Hide new GUI as we do not want to show it accidentally
+        sheet:hide()
+    end
+    return sheet
+end
+
+local function hideCursor()
+    if cursor:isVisible() then
+        cursor:hide()
+    end
+end
+
+local function showCursor()
+    if not cursor:isVisible() and orxonox.InputManager:getInstance():isMouseExclusive() then
+        cursor:show()
+    end
+end
+
+local function find(table, value)
+    for i, v in ipairs(table) do
+        if v == value then
+            return i
         end
-        -- hide new GUI as we do not want to show it accidentially
-        loadedGui:hide()
     end
-    return loadedGui
+    return nil
 end
 
-function showGUI(filename, hidePrevious, bCursorVisible, ptr)
-    gui = showGUI(filename, hidePrevious, bCursorVisible)
+
+------------------------
+--- Global functions ---
+------------------------
+
+-- ?
+function showGUI(name, bHidePrevious, bShowCursor, ptr)
+    gui = showGUI(name, bHidePrevious, bShowCursor)
     gui.overlay = ptr
 end
 
--- shows the specified GUI sheet and loads it if not loaded already
-function showGUI(filename, hidePrevious, bCursorVisible)
-    if bCursorVisible == nil then
-        if nrOfActiveSheets > 0 then
-            bCursorVisible = cursorVisibility[activeSheets[nrOfActiveSheets]]
+-- Shows the specified menu sheet and loads it if neccessary
+function showGUI(name, bHidePrevious, bShowCursor)
+    -- Handle default value for bShowCursor
+    if bShowCursor == nil then
+        if activeMenuSheets.size > 0 then
+            bShowCursor = activeMenuSheets.topSheet.bShowCursor
         else
-            bCursorVisible = true
+            bShowCursor = true
         end
     end
 
-    if root == nil then
+    -- Hide if already displayed (to make sure it is up front in the end)
+    if activeMenuSheets[name] ~= nil then
+        hideGUI(name)
+    end
+
+    if not root then
         setBackground("")
     end
 
-    local currentGUI = loadedGUIs[filename]
-    if(currentGUI == nil) then
-        currentGUI = loadGUI(filename)
+    -- Get sheet (or load it)
+    local menuSheet = loadSheet(name)
+    if not menuSheet then
+        return
     end
 
-    if(root:isChild(currentGUI.window)) then
-        root:removeChildWindow(currentGUI.window)
+    -- Add sheet to the root window
+    root:addChildWindow(menuSheet.window)
+
+    -- Pause game control if this is the first menu to be displayed
+    -- HUGE HACK?
+    if activeMenuSheets.size == 0 then
+        orxonox.HumanController:pauseControl()
     end
-    root:addChildWindow(currentGUI.window)
 
-    if bCursorVisible then
+    -- Handle input distribution
+    orxonox.InputManager:getInstance():enterState(menuSheet.inputState)
+
+    if bShowCursor then
         showCursor()
     else
         hideCursor()
     end
 
-    if find( activeSheets, filename ) ~= nil then
-        table.remove( activeSheets, find( activeSheets, filename ) )
-        nrOfActiveSheets = nrOfActiveSheets - 1
-    else
-        if nrOfActiveSheets == 0 then
-            --orxonox.InputManager:getInstance():enterState("guiMouseOnly")
-            orxonox.HumanController:pauseControl()
-        end
-    end
-    orxonox.InputManager:getInstance():enterState(currentGUI.inputState)
+    -- Add the sheet in a tuple of additional information
+    local sheetTuple =
+    {
+        ["menuSheet"]      = menuSheet,
+        ["name"]           = name,
+        ["bShowCursor"]    = bShowCursor,
+        ["bHidePrevious"]  = bHidePrevious
+    }
+    table.insert(activeMenuSheets, sheetTuple) -- indexed array access
+    activeMenuSheets[name] = sheetTuple -- name access
+    activeMenuSheets.size = activeMenuSheets.size + 1
+    activeMenuSheets.topSheet = sheetTuple
 
-    nrOfActiveSheets = nrOfActiveSheets + 1
-    table.insert(activeSheets, filename)
-    activeSheets[nrOfActiveSheets] = filename
-    bHidePrevious[filename]=hidePrevious
-    cursorVisibility[filename] = bCursorVisible
-
-    if hidePrevious == true then
-        for i=1,nrOfActiveSheets-1 do
-            loadedGUIs[ activeSheets[i] ]:hide()
+    -- Hide all previous sheets if necessary
+    if bHidePrevious then
+        for i = 1, activeMenuSheets.size - 1 do
+            activeMenuSheets[i].menuSheet:hide()
         end
     end
-    currentGUI:show()
-    return currentGUI
-end
 
-function hideCursor()
-    if bShowsCursor==true then
-        bShowsCursor=false
-        cursor:hide()
-    end
+    menuSheet:show()
+    return menuSheet
 end
 
-function showCursor()
-    if bShowsCursor==false then
-        bShowsCursor=true
-        cursor:show()
+function hideGUI(name)
+    local sheetTuple = activeMenuSheets[name]
+    if sheetTuple == nil then
+        return
     end
-end
 
-function hideGUI(filename)
-    local currentGUI = loadedGUIs[filename]
-    if currentGUI == nil then
-        return
-    end
-    currentGUI:hide()
-    if bHidePrevious[filename] == true then
-        local i = nrOfActiveSheets-1
-        while i>0 do
-            loadedGUIs[ activeSheets[i] ]:show()
-            if bHidePrevious[filename]==true then
-                break
-            else
-                i=i-1
-            end
-        end
-    end
-    root:removeChildWindow(currentGUI.window)
-    local i=1
-    while activeSheets[i] do
-        if activeSheets[i+1] == nil then
-            if activeSheets[i-1] ~= nil then
-                if cursorVisibility[ activeSheets[i-1] ] == true then
-                    showCursor()
-                else
-                    hideCursor()
+    -- Hide the sheet
+    sheetTuple.menuSheet:hide()
+
+    -- Show sheets that were hidden by the sheet to be removed
+    local i = activeMenuSheets.size
+    -- Only do something if all sheets on top of sheetTuple
+    -- have bHidePrevious == false and sheetTuple.bHidePrevious == true
+    while i > 0 do
+        if activeMenuSheets[i].bHidePrevious == true then
+            if activeMenuSheets[i] == sheetTuple then
+                i = i - 1
+                while i > 0 do
+                    activeMenuSheets[i].menuSheet:show()
+                    if activeMenuSheets[i].bHidePrevious == true then
+                        break
+                    end
+                    i = i - 1
                 end
-            else
-                hideCursor()
             end
+            break
         end
-        if activeSheets[i] == filename then
-            table.remove( activeSheets, i )
-            nrOfActiveSheets = nrOfActiveSheets-1
-        else
-            i = i+1
-        end
+        i = i - 1
     end
-    cursorVisibility[filename] = nil -- remove the cursor visibility of the current gui from the table
-    bHidePrevious[filename] = nil
-    if nrOfActiveSheets == 0 then
-        --orxonox.InputManager:getInstance():leaveState("guiMouseOnly")
+
+    -- Remove sheet with its tuple from the table
+    root:removeChildWindow(sheetTuple.menuSheet.window)
+    table.remove(activeMenuSheets, find(activeMenuSheets, sheetTuple))
+    activeMenuSheets[name] = nil
+    activeMenuSheets.size = activeMenuSheets.size - 1
+    activeMenuSheets.topSheet = activeMenuSheets[activeMenuSheets.size]
+
+    -- Leave the input state
+    orxonox.InputManager:getInstance():leaveState(sheetTuple.menuSheet.inputState)
+    
+    -- See whether to show or hide cursor
+    if activeMenuSheets.size > 0 and activeMenuSheets.topSheet.bShowCursor then
+        showCursor()
+    else
+        hideCursor()
+    end
+
+    -- Resume control if the last menu is hidden
+    if activeMenuSheets.size == 0 then
         orxonox.HumanController:resumeControl()
         hideCursor()
     end
-    orxonox.InputManager:getInstance():leaveState(currentGUI.inputState)
 end
 
+-- Hides all menu GUI sheets
 function hideAllGUIs()
-    while nrOfActiveSheets ~= 0 do
-        hideGUI(activeSheets[nrOfActiveSheets])
+    while activeMenuSheets.size ~= 0 do
+        hideGUI(activeMenuSheets.topSheet.name)
     end
 end
 
 function keyESC()
-    if nrOfActiveSheets == 1 and activeSheets[1] == "MainMenu" then
+    -- HUGE, very HUGE hacks!
+    if activeMenuSheets.size == 1 and activeMenuSheets[1].name == "MainMenu" then
         orxonox.execute("exit")
-    elseif nrOfActiveSheets > 0 then
-        orxonox.execute("hideGUI "..activeSheets[nrOfActiveSheets])
+    elseif activeMenuSheets.size > 0 then
+        orxonox.execute("hideGUI "..activeMenuSheets.topSheet.name)
     else
         showGUI("InGameMenu")
     end
 end
 
-function setBackground(filename)
+function setBackground(name)
     local newroot
     if root ~= nil then
         root:rename("oldRootWindow")
     end
-    if filename ~= "" then
-        newroot = winMgr:loadWindowLayout(filename .. ".layout")
+    if name ~= "" then
+        newroot = winMgr:loadWindowLayout(name .. ".layout")
         newroot:rename("AbsoluteRootWindow")
         system:setGUISheet(newroot)
     else
@@ -227,19 +260,3 @@
     newroot:show()
     root = newroot
 end
-
-function find(table, value)
-    local i=0
-    while table[i] ~= nil do
-        if table[i]==value then
-            return i
-        else
-            i=i+1
-        end
-    end
-    return nil
-end
-
-function test(e)
-    debug(0, "Blubb")
-end

Modified: code/branches/gamestates2/data/gui/scripts/KeyBindMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/KeyBindMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/KeyBindMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,16 +1,9 @@
 -- KeyBindMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("KeyBindMenu")
+local P = createSheet("KeyBindMenu")
 
-if _REQUIREDNAME == nil then
-    KeyBindMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+function P.init()
 
-function P:init()
-
     commandList = {}
     table.insert(commandList, "fire 0")
     table.insert(commandList, "fire 1 | unfire")

Modified: code/branches/gamestates2/data/gui/scripts/MainMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/MainMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/MainMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- MainMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("MainMenu")
-if _REQUIREDNAME == nil then
-    MainMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("MainMenu")
 
 -- events for MainMenu
 function P.QuickGameTestButton_clicked(e)

Modified: code/branches/gamestates2/data/gui/scripts/MouseControlsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/MouseControlsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/MouseControlsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- MouseControlsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("MouseControlsMenu")
-if _REQUIREDNAME == nil then
-    MouseControlsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("MouseControlsMenu")
 
-function P:init()
+function P.init()
     block = false
     mousenormalscrollbarwindow = tolua.cast(winMgr:getWindow("orxonox/MouseNormalScrollbar"),"CEGUI::Scrollbar")
     mousederivescrollbarwindow = tolua.cast(winMgr:getWindow("orxonox/MouseDeriveScrollbar"),"CEGUI::Scrollbar")

Modified: code/branches/gamestates2/data/gui/scripts/MultiplayerMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/MultiplayerMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/MultiplayerMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- MultiplayerMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("MultiplayerMenu")
-if _REQUIREDNAME == nil then
-    MultiplayerMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("MultiplayerMenu")
 
-function P:init()
+function P.init()
     listbox = winMgr:getWindow("orxonox/MultiplayerLevelListbox")
     preselect = orxonox.LevelManager:getInstance():getDefaultLevel()
     orxonox.LevelManager:getInstance():compileAvailableLevelList()

Modified: code/branches/gamestates2/data/gui/scripts/MultiplayerOptionsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/MultiplayerOptionsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/MultiplayerOptionsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- MultiplayerOptionsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("MultiplayerOptionsMenu")
-if _REQUIREDNAME == nil then
-    MultiplayerOptionsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("MultiplayerOptionsMenu")
 
 function P.MultiplayerOptionsBackButton_clicked(e)
     hideGUI(P.filename)

Modified: code/branches/gamestates2/data/gui/scripts/PickupInventory.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/PickupInventory.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/PickupInventory.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,24 +1,18 @@
 -- PickupInventory.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("PickupInventory")
-if _REQUIREDNAME == nil then
-    PickupInventory = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("PickupInventory")
 
 P.lastEquipmentCount_ = 0
 P.lastUsableCount_ = 0
 P.currentUsableID_ = 0
 
 -- events
-function P:frmUpdate(e)
+function P.frmUpdate(e)
     local equipCount = orxonox.PickupInventory:getEquipmentCount()
     local usableCount = orxonox.PickupInventory:getUsableCount()
 
-    if equipCount ~= self.lastEquipmentCount_ or usableCount ~= self.lastUsableCount_ then
-        self:updateTabs()
+    if equipCount ~= P.lastEquipmentCount_ or usableCount ~= P.lastUsableCount_ then
+        P.updateTabs()
     end
 end
 
@@ -30,7 +24,7 @@
     loadedGUIs["PickupInventory"]:mItemClicked(e)
 end
 
-function P:mItemClicked(e)
+function P.mItemClicked(e)
     local w = CEGUI.toWindowEventArgs(e).window
     local name = w:getName()
     local t = name:sub(25, 27)
@@ -41,25 +35,25 @@
     end
 
     if t == "use" then
-        if self.currentUsableID_ >= 0 then
-            winMgr:getWindow("orxonox/Inventory/Title/use/" .. self.currentUsableID_):setProperty("TextColours", "tl:FFFFFFFF tr:FFFFFFFF bl:FFFFFFFF br:FFFFFFFF")
+        if P.currentUsableID_ >= 0 then
+            winMgr:getWindow("orxonox/Inventory/Title/use/" .. P.currentUsableID_):setProperty("TextColours", "tl:FFFFFFFF tr:FFFFFFFF bl:FFFFFFFF br:FFFFFFFF")
         end
         orxonox.PickupInventory:selectUsable(tonumber(i))
-        self.currentUsableID_ = tonumber(i)
+        P.currentUsableID_ = tonumber(i)
         winMgr:getWindow("orxonox/Inventory/Title/use/" .. i):setProperty("TextColours", "tl:FFFF4444 tr:FFFF4444 bl:FFFF4444 br:FFFF4444")
     end
 end
 
 -- methods
-function P:updateTabs()
+function P.updateTabs()
     local eqWin = winMgr:getWindow("orxonox/Inventory/TabControl/TabEquipment")
     local usWin = winMgr:getWindow("orxonox/Inventory/TabControl/TabUsable")
     orxonox.PickupInventory:getSingleton():clearInventory(winMgr, eqWin, usWin)
     orxonox.PickupInventory:getSingleton():updateTabs(winMgr, eqWin, usWin)
 
-    self.currentUsableID_ = orxonox.PickupInventory:getCurrentUsableIndex()
-    self.lastEquipmentCount_ = orxonox.PickupInventory:getEquipmentCount()
-    self.lastUsableCount_ = orxonox.PickupInventory:getUsableCount()
+    P.currentUsableID_ = orxonox.PickupInventory:getCurrentUsableIndex()
+    P.lastEquipmentCount_ = orxonox.PickupInventory:getEquipmentCount()
+    P.lastUsableCount_ = orxonox.PickupInventory:getUsableCount()
 end
 
 return P

Modified: code/branches/gamestates2/data/gui/scripts/QuestGUI.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/QuestGUI.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/QuestGUI.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,15 +1,11 @@
-gui = require("BasicGUI")
-local P = BasicGUI:new("QuestGUI")
-if _REQUIREDNAME == nil then
-    QuestGUI = P
-else
-    _G[_REQUIREDNAME] = P
-end
+-- QuestGUI.lua
 
-function P:show()
-    self.window:show() -- TDO: Do this through parent...
-    self.visible = true
+local P = createSheet("QuestGUI")
 
+function P.show()
+    P.window:show() -- TDO: Do this through parent...
+    P.visible = true
+
     local questManager = orxonox.QuestManager:getInstance()
 
     local questsList = winMgr:getWindow("orxonox/QuestGUI/QuestsList")

Modified: code/branches/gamestates2/data/gui/scripts/SettingsMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/SettingsMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/SettingsMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,12 +1,6 @@
 -- SettingsMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("SettingsMenu")
-if _REQUIREDNAME == nil then
-    SettingsMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("SettingsMenu")
 
 function P.SettingsGameplayButton_clicked(e)
     showGUI("GameplayMenu", true)
@@ -30,7 +24,7 @@
 
 function P.SettingsResetSettingsButton_clicked(e)
     -- reset settings
-    debug("event: reset settings")
+    logMessage(0, "event: reset settings")
 end
 
 function P.SettingsBackButton_clicked(e)

Modified: code/branches/gamestates2/data/gui/scripts/SingleplayerMenu.lua
===================================================================
--- code/branches/gamestates2/data/gui/scripts/SingleplayerMenu.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/gui/scripts/SingleplayerMenu.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,14 +1,8 @@
 -- SingleplayerMenu.lua
 
-BasicGUI = require("BasicGUI")
-local P = BasicGUI:new("SingleplayerMenu")
-if _REQUIREDNAME == nil then
-    SingleplayerMenu = P
-else
-    _G[_REQUIREDNAME] = P
-end
+local P = createSheet("SingleplayerMenu")
 
-function P:init()
+function P.init()
     listbox = winMgr:getWindow("orxonox/SingleplayerLevelListbox")
     preselect = orxonox.LevelManager:getInstance():getDefaultLevel()
     orxonox.LevelManager:getInstance():compileAvailableLevelList()

Copied: code/branches/gamestates2/data/lua/Debugger.lua (from rev 6661, code/branches/gamestate/data/lua/Debugger.lua)
===================================================================
--- code/branches/gamestates2/data/lua/Debugger.lua	                        (rev 0)
+++ code/branches/gamestates2/data/lua/Debugger.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -0,0 +1,1358 @@
+
+--{{{  history
+
+--28/03/10 ORX Adjusted show() to work with the Orxonox resource system
+--15/03/06 DCN Created based on RemDebug
+--28/04/06 DCN Update for Lua 5.1
+--01/06/06 DCN Fix command argument parsing
+--             Add step/over N facility
+--             Add trace lines facility
+--05/06/06 DCN Add trace call/return facility
+--06/06/06 DCN Make it behave when stepping through the creation of a coroutine
+--06/06/06 DCN Integrate the simple debugger into the main one
+--07/06/06 DCN Provide facility to step into coroutines
+--13/06/06 DCN Fix bug that caused the function environment to get corrupted with the global one
+--14/06/06 DCN Allow 'sloppy' file names when setting breakpoints
+--04/08/06 DCN Allow for no space after command name
+--11/08/06 DCN Use io.write not print
+--30/08/06 DCN Allow access to array elements in 'dump'
+--10/10/06 DCN Default to breakfile for all commands that require a filename and give '-'
+--06/12/06 DCN Allow for punctuation characters in DUMP variable names
+--03/01/07 DCN Add pause on/off facility
+--19/06/07 DCN Allow for duff commands being typed in the debugger (thanks to Michael.Bringmann at lsi.com)
+--             Allow for case sensitive file systems               (thanks to Michael.Bringmann at lsi.com)
+
+--}}}
+--{{{  description
+
+--A simple command line debug system for Lua written by Dave Nichols of
+--Match-IT Limited. Its public domain software. Do with it as you wish.
+
+--This debugger was inspired by:
+-- RemDebug 1.0 Beta
+-- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug)
+
+--Usage:
+--  require('debugger')        --load the debug library
+--  pause(message)             --start/resume a debug session
+
+--An assert() failure will also invoke the debugger.
+
+--}}}
+
+local IsWindows = string.find(string.lower(os.getenv('OS') or ''),'^windows')
+
+local coro_debugger
+local events = { BREAK = 1, WATCH = 2, STEP = 3, SET = 4 }
+local breakpoints = {}
+local watches = {}
+local step_into   = false
+local step_over   = false
+local step_lines  = 0
+local step_level  = {main=0}
+local stack_level = {main=0}
+local trace_level = {main=0}
+local trace_calls = false
+local trace_returns = false
+local trace_lines = false
+local ret_file, ret_line, ret_name
+local current_thread = 'main'
+local started = false
+local pause_off = false
+local _g      = _G
+local cocreate, cowrap = coroutine.create, coroutine.wrap
+local pausemsg = 'pause'
+
+--{{{  local hints -- command help
+--The format in here is name=summary|description
+local hints = {
+
+pause =   [[
+pause(msg)          -- start/resume a debugger session|
+
+This can only be used in your code or from the console as a means to
+start/resume a debug session.
+If msg is given that is shown when the session starts/resumes. Useful to
+give a context if you've instrumented your code with pause() statements.
+]],
+
+poff =    [[
+poff                -- turn off pause() command|
+
+This causes all pause() commands to be ignored. This is useful if you have
+instrumented your code in a busy loop and want to continue normal execution
+with no further interruption.
+]],
+
+pon =     [[
+pon                 -- turn on pause() command|
+
+This re-instates honouring the pause() commands you may have instrumented
+your code with.
+]],
+
+setb =    [[
+setb [line file]    -- set a breakpoint to line/file|
+
+If file is omitted or is "-" the breakpoint is set at the file for the
+currently set level (see "set"). Execution pauses when this line is about
+to be executed and the debugger session is re-activated.
+
+The file can be given as the fully qualified name, partially qualified or
+just the file name. E.g. if file is set as "myfile.lua", then whenever
+execution reaches any file that ends with "myfile.lua" it will pause.
+]],
+
+delb =    [[
+delb [line file]    -- removes a breakpoint|
+
+If file is omitted or is "-" the breakpoint is removed for the file of the
+currently set level (see "set").
+]],
+
+delallb = [[
+delallb             -- removes all breakpoints|
+]],
+
+setw =    [[
+setw <exp>          -- adds a new watch expression|
+
+The expression is evaluated before each line is executed. If the expression
+yields true then execution is paused and the debugger session re-activated.
+The expression is executed in the context of the line about to be executed.
+]],
+
+delw =    [[
+delw <index>        -- removes the watch expression at index|
+
+The index is that returned when the watch expression was set by setw.
+]],
+
+delallw = [[
+delallw             -- removes all watch expressions|
+]],
+
+run     = [[
+run                 -- run until next breakpoint or watch expression|
+]],
+
+step    = [[
+step [N]            -- run next N lines, stepping into function calls|
+
+If N is omitted, use 1.
+]],
+
+over    = [[
+over [N]            -- run next N lines, stepping over function calls|
+
+If N is omitted, use 1.
+]],
+
+out     = [[
+out [N]             -- run lines until stepped out of N functions|
+
+If N is omitted, use 1.
+If you are inside a function, using "out 1" will run until you return
+from that function to the caller.
+]],
+
+goto    = [[
+goto <line>         -- step to line number <line> in the current file|
+
+The line and current file are those in the currently set context level.
+]],
+
+listb   = [[
+listb               -- lists breakpoints|
+]],
+
+listw   = [[
+listw               -- lists watch expressions|
+]],
+
+set     = [[
+set [level]         -- set context to stack level, omitted=show|
+
+If level is omitted it just prints the current level set.
+This sets the current context to the level given. This affects the
+context used for several other functions (e.g. vars). The possible
+levels are those shown by trace.
+]],
+
+vars    = [[
+vars [depth]        -- list context locals to depth, omitted=1|
+
+If depth is omitted then uses 1.
+Use a depth of 0 for the maximum.
+Lists all non-nil local variables and all non-nil upvalues in the
+currently set context. For variables that are tables, lists all fields
+to the given depth.
+]],
+
+fenv    = [[
+fenv [depth]        -- list context function env to depth, omitted=1|
+
+If depth is omitted then uses 1.
+Use a depth of 0 for the maximum.
+Lists all function environment variables in the currently set context.
+For variables that are tables, lists all fields to the given depth.
+]],
+
+glob    = [[
+glob [depth]        -- list globals to depth, omitted=1|
+
+If depth is omitted then uses 1.
+Use a depth of 0 for the maximum.
+Lists all global variables.
+For variables that are tables, lists all fields to the given depth.
+]],
+
+ups     = [[
+ups                 -- list all the upvalue names|
+
+These names will also be in the "vars" list unless their value is nil.
+This provides a means to identify which vars are upvalues and which are
+locals. If a name is both an upvalue and a local, the local value takes
+precedance.
+]],
+
+locs    = [[
+locs                -- list all the locals names|
+
+These names will also be in the "vars" list unless their value is nil.
+This provides a means to identify which vars are upvalues and which are
+locals. If a name is both an upvalue and a local, the local value takes
+precedance.
+]],
+
+dump    = [[
+dump <var> [depth]  -- dump all fields of variable to depth|
+
+If depth is omitted then uses 1.
+Use a depth of 0 for the maximum.
+Prints the value of <var> in the currently set context level. If <var>
+is a table, lists all fields to the given depth. <var> can be just a
+name, or name.field or name.# to any depth, e.g. t.1.f accesses field
+'f' in array element 1 in table 't'.
+
+Can also be called from a script as dump(var,depth).
+]],
+
+tron    = [[
+tron [crl]          -- turn trace on for (c)alls, (r)etuns, (l)lines|
+
+If no parameter is given then tracing is turned off.
+When tracing is turned on a line is printed to the console for each
+debug 'event' selected. c=function calls, r=function returns, l=lines.
+]],
+
+trace   = [[
+trace               -- dumps a stack trace|
+
+Format is [level] = file,line,name
+The level is a candidate for use by the 'set' command.
+]],
+
+info    = [[
+info                -- dumps the complete debug info captured|
+
+Only useful as a diagnostic aid for the debugger itself. This information
+can be HUGE as it dumps all variables to the maximum depth, so be careful.
+]],
+
+show    = [[
+show line file X Y  -- show X lines before and Y after line in file|
+
+If line is omitted or is '-' then the current set context line is used.
+If file is omitted or is '-' then the current set context file is used.
+If file is not fully qualified and cannot be opened as specified, then
+a search for the file in the package[path] is performed using the usual
+"require" searching rules. If no file extension is given, .lua is used.
+Prints the lines from the source file around the given line.
+]],
+
+exit    = [[
+exit                -- exits debugger, re-start it using pause()|
+]],
+
+help    = [[
+help [command]      -- show this list or help for command|
+]],
+
+["<statement>"] = [[
+<statement>         -- execute a statement in the current context|
+
+The statement can be anything that is legal in the context, including
+assignments. Such assignments affect the context and will be in force
+immediately. Any results returned are printed. Use '=' as a short-hand
+for 'return', e.g. "=func(arg)" will call 'func' with 'arg' and print
+the results, and "=var" will just print the value of 'var'.
+]],
+
+what    = [[
+what <func>         -- show where <func> is defined (if known)|
+]],
+
+}
+--}}}
+
+--{{{  local function getinfo(level,field)
+
+--like debug.getinfo but copes with no activation record at the given level
+--and knows how to get 'field'. 'field' can be the name of any of the
+--activation record fields or any of the 'what' names or nil for everything.
+--only valid when using the stack level to get info, not a function name.
+
+local function getinfo(level,field)
+  level = level + 1  --to get to the same relative level as the caller
+  if not field then return debug.getinfo(level) end
+  local what
+  if field == 'name' or field == 'namewhat' then
+    what = 'n'
+  elseif field == 'what' or field == 'source' or field == 'linedefined' or field == 'lastlinedefined' or field == 'short_src' then
+    what = 'S'
+  elseif field == 'currentline' then
+    what = 'l'
+  elseif field == 'nups' then
+    what = 'u'
+  elseif field == 'func' then
+    what = 'f'
+  else
+    return debug.getinfo(level,field)
+  end
+  local ar = debug.getinfo(level,what)
+  if ar then return ar[field] else return nil end
+end
+
+--}}}
+--{{{  local function indented( level, ... )
+
+local function indented( level, ... )
+  io.write( string.rep('  ',level), table.concat({...}), '\n' )
+end
+
+--}}}
+--{{{  local function dumpval( level, name, value, limit )
+
+local dumpvisited
+
+local function dumpval( level, name, value, limit )
+  local index
+  if type(name) == 'number' then
+    index = string.format('[%d] = ',name)
+  elseif type(name) == 'string'
+     and (name == '__VARSLEVEL__' or name == '__ENVIRONMENT__' or name == '__GLOBALS__' or name == '__UPVALUES__' or name == '__LOCALS__') then
+    --ignore these, they are debugger generated
+    return
+  elseif type(name) == 'string' and string.find(name,'^[_%a][_.%w]*$') then
+    index = name ..' = '
+  else
+    index = string.format('[%q] = ',tostring(name))
+  end
+  if type(value) == 'table' then
+    if dumpvisited[value] then
+      indented( level, index, string.format('ref%q;',dumpvisited[value]) )
+    else
+      dumpvisited[value] = tostring(value)
+      if (limit or 0) > 0 and level+1 >= limit then
+        indented( level, index, dumpvisited[value] )
+      else
+        indented( level, index, '{  -- ', dumpvisited[value] )
+        for n,v in pairs(value) do
+          dumpval( level+1, n, v, limit )
+        end
+        indented( level, '};' )
+      end
+    end
+  else
+    if type(value) == 'string' then
+      if string.len(value) > 40 then
+        indented( level, index, '[[', value, ']];' )
+      else
+        indented( level, index, string.format('%q',value), ';' )
+      end
+    else
+      indented( level, index, tostring(value), ';' )
+    end
+  end
+end
+
+--}}}
+--{{{  local function dumpvar( value, limit, name )
+
+local function dumpvar( value, limit, name )
+  dumpvisited = {}
+  dumpval( 0, name or tostring(value), value, limit )
+end
+
+--}}}
+--{{{  local function show(file,line,before,after)
+
+--show +/-N lines of a file around line M
+
+local function show(file,line,before,after)
+
+  line   = tonumber(line   or 1)
+  before = tonumber(before or 10)
+  after  = tonumber(after  or before)
+
+  -- Try to find the file in the Orxonox resources
+  local text = luaState:getSourceCode(file)
+
+  if text == "" then
+    if not string.find(file,'%.') then file = file..'.lua' end
+
+    local f = io.open(file,'r')
+    if not f then
+      --{{{  try to find the file in the path
+    
+      --
+      -- looks for a file in the package path
+      --
+      local path = package.path or LUA_PATH or ''
+      for c in string.gmatch (path, "[^;]+") do
+        local c = string.gsub (c, "%?%.lua", file)
+        f = io.open (c,'r')
+        if f then
+          break
+        end
+      end
+    
+      --}}}
+
+      if f then
+        -- Read file into 'text'
+        text = f:read("*a")
+        f:close()
+      else
+        io.write('Cannot find '..file..'\n')
+        return
+      end
+    end
+  end
+
+  -- Transform line endings to \n
+  text:gsub("\r\n", "\n") -- Windows to Unix
+  text:gsub("\r", "\n")   -- Mac to Unix
+  if text[-1] ~= "\n" then
+      text = text.."\n"
+  end
+  -- Print requested lines
+  local i = 0
+  for l in text:gmatch("[^\n]*[\n]") do
+    i = i + 1
+    if i >= (line-before) then
+      if i > (line+after) then break end
+      if i == line then
+        io.write(i..'***\t'..l)
+      else
+        io.write(i..'\t'..l)
+      end
+    end
+  end
+end
+
+--}}}
+--{{{  local function tracestack(l)
+
+local function gi( i )
+  return function() i=i+1 return debug.getinfo(i),i end
+end
+
+local function gl( level, j )
+  return function() j=j+1 return debug.getlocal( level, j ) end
+end
+
+local function gu( func, k )
+  return function() k=k+1 return debug.getupvalue( func, k ) end
+end
+
+local  traceinfo
+
+local function tracestack(l)
+  local l = l + 1                        --NB: +1 to get level relative to caller
+  traceinfo = {}
+  traceinfo.pausemsg = pausemsg
+  for ar,i in gi(l) do
+    table.insert( traceinfo, ar )
+    local names  = {}
+    local values = {}
+    for n,v in gl(i,0) do
+      if string.sub(n,1,1) ~= '(' then   --ignore internal control variables
+        table.insert( names, n )
+        table.insert( values, v )
+      end
+    end
+    if #names > 0 then
+      ar.lnames  = names
+      ar.lvalues = values
+    end
+    if ar.func then
+      local names  = {}
+      local values = {}
+      for n,v in gu(ar.func,0) do
+        if string.sub(n,1,1) ~= '(' then   --ignore internal control variables
+          table.insert( names, n )
+          table.insert( values, v )
+        end
+      end
+      if #names > 0 then
+        ar.unames  = names
+        ar.uvalues = values
+      end
+    end
+  end
+end
+
+--}}}
+--{{{  local function trace()
+
+local function trace(set)
+  local mark
+  for level,ar in ipairs(traceinfo) do
+    if level == set then
+      mark = '***'
+    else
+      mark = ''
+    end
+    io.write('['..level..']'..mark..'\t'..(ar.name or ar.what)..' in '..ar.short_src..':'..ar.currentline..'\n')
+  end
+end
+
+--}}}
+--{{{  local function info()
+
+local function info() dumpvar( traceinfo, 0, 'traceinfo' ) end
+
+--}}}
+
+--{{{  local function set_breakpoint(file, line)
+
+local function set_breakpoint(file, line)
+  if not breakpoints[line] then
+    breakpoints[line] = {}
+  end
+  breakpoints[line][file] = true
+end
+
+--}}}
+--{{{  local function remove_breakpoint(file, line)
+
+local function remove_breakpoint(file, line)
+  if breakpoints[line] then
+    breakpoints[line][file] = nil
+  end
+end
+
+--}}}
+--{{{  local function has_breakpoint(file, line)
+
+--allow for 'sloppy' file names
+--search for file and all variations walking up its directory hierachy
+--ditto for the file with no extension
+
+local function has_breakpoint(file, line)
+  if not breakpoints[line] then return false end
+  local noext = string.gsub(file,"(%..-)$",'',1)
+  if noext == file then noext = nil end
+  while file do
+    if breakpoints[line][file] then return true end
+    file = string.match(file,"[:/\](.+)$")
+  end
+  while noext do
+    if breakpoints[line][noext] then return true end
+    noext = string.match(noext,"[:/\](.+)$")
+  end
+  return false
+end
+
+--}}}
+--{{{  local function capture_vars(ref,level,line)
+
+local function capture_vars(ref,level,line)
+  --get vars, file and line for the given level relative to debug_hook offset by ref
+
+  local lvl = ref + level                --NB: This includes an offset of +1 for the call to here
+
+  --{{{  capture variables
+  
+  local ar = debug.getinfo(lvl, "f")
+  if not ar then return {},'?',0 end
+  
+  local vars = {__UPVALUES__={}, __LOCALS__={}}
+  local i
+  
+  local func = ar.func
+  if func then
+    i = 1
+    while true do
+      local name, value = debug.getupvalue(func, i)
+      if not name then break end
+      if string.sub(name,1,1) ~= '(' then  --NB: ignoring internal control variables
+        vars[name] = value
+        vars.__UPVALUES__[i] = name
+      end
+      i = i + 1
+    end
+    vars.__ENVIRONMENT__ = getfenv(func)
+  end
+  
+  vars.__GLOBALS__ = getfenv(0)
+  
+  i = 1
+  while true do
+    local name, value = debug.getlocal(lvl, i)
+    if not name then break end
+    if string.sub(name,1,1) ~= '(' then    --NB: ignoring internal control variables
+      vars[name] = value
+      vars.__LOCALS__[i] = name
+    end
+    i = i + 1
+  end
+  
+  vars.__VARSLEVEL__ = level
+  
+  if func then
+    --NB: Do not do this until finished filling the vars table
+    setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) })
+  end
+  
+  --NB: Do not read or write the vars table anymore else the metatable functions will get invoked!
+  
+  --}}}
+
+  local file = getinfo(lvl, "source")
+  if string.find(file, "@") == 1 then
+    file = string.sub(file, 2)
+  end
+  -- Orxonox changes: Our resource system is case sensisive, even on Windows
+  --if IsWindows then file = string.lower(file) end
+
+  if not line then
+    line = getinfo(lvl, "currentline")
+  end
+
+  return vars,file,line
+
+end
+
+--}}}
+--{{{  local function restore_vars(ref,vars)
+
+local function restore_vars(ref,vars)
+
+  if type(vars) ~= 'table' then return end
+
+  local level = vars.__VARSLEVEL__       --NB: This level is relative to debug_hook offset by ref
+  if not level then return end
+
+  level = level + ref                    --NB: This includes an offset of +1 for the call to here
+
+  local i
+  local written_vars = {}
+
+  i = 1
+  while true do
+    local name, value = debug.getlocal(level, i)
+    if not name then break end
+    if vars[name] and string.sub(name,1,1) ~= '(' then     --NB: ignoring internal control variables
+      debug.setlocal(level, i, vars[name])
+      written_vars[name] = true
+    end
+    i = i + 1
+  end
+
+  local ar = debug.getinfo(level, "f")
+  if not ar then return end
+
+  local func = ar.func
+  if func then
+
+    i = 1
+    while true do
+      local name, value = debug.getupvalue(func, i)
+      if not name then break end
+      if vars[name] and string.sub(name,1,1) ~= '(' then   --NB: ignoring internal control variables
+        if not written_vars[name] then
+          debug.setupvalue(func, i, vars[name])
+        end
+        written_vars[name] = true
+      end
+      i = i + 1
+    end
+
+  end
+
+end
+
+--}}}
+--{{{  local function trace_event(event, line, level)
+
+local function print_trace(level,depth,event,file,line,name)
+
+  --NB: level here is relative to the caller of trace_event, so offset by 2 to get to there
+  level = level + 2
+
+  local file = file or getinfo(level,'short_src')
+  local line = line or getinfo(level,'currentline')
+  local name = name or getinfo(level,'name')
+
+  local prefix = ''
+  if current_thread ~= 'main' then prefix = '['..tostring(current_thread)..'] ' end
+
+  io.write(prefix..
+           string.format('%08.2f:%02i.',os.clock(),depth)..
+           string.rep('.',depth%32)..
+           (file or '')..' ('..(line or '')..') '..
+           (name or '')..
+           ' ('..event..')\n')
+
+end
+
+local function trace_event(event, line, level)
+
+  if event == 'return' and trace_returns then
+    --note the line info for later
+    ret_file = getinfo(level+1,'short_src')
+    ret_line = getinfo(level+1,'currentline')
+    ret_name = getinfo(level+1,'name')
+  end
+
+  if event ~= 'line' then return end
+
+  local slevel = stack_level[current_thread]
+  local tlevel = trace_level[current_thread]
+
+  if trace_calls and slevel > tlevel then
+    --we are now in the function called, so look back 1 level further to find the calling file and line
+    print_trace(level+1,slevel-1,'c',nil,nil,getinfo(level+1,'name'))
+  end
+
+  if trace_returns and slevel < tlevel then
+    print_trace(level,slevel,'r',ret_file,ret_line,ret_name)
+  end
+
+  if trace_lines then
+    print_trace(level,slevel,'l')
+  end
+
+  trace_level[current_thread] = stack_level[current_thread]
+
+end
+
+--}}}
+--{{{  local function debug_hook(event, line, level, thread)
+
+local function debug_hook(event, line, level, thread)
+  if not started then debug.sethook() return end
+  current_thread = thread or 'main'
+  local level = level or 2
+  trace_event(event,line,level)
+  if event == "call" then
+    stack_level[current_thread] = stack_level[current_thread] + 1
+  elseif event == "return" then
+    stack_level[current_thread] = stack_level[current_thread] - 1
+    if stack_level[current_thread] < 0 then stack_level[current_thread] = 0 end
+  else
+    local vars,file,line = capture_vars(level,1,line)
+    local stop, ev, idx = false, events.STEP, 0
+    while true do
+      for index, value in pairs(watches) do
+        setfenv(value.func, vars)
+        local status, res = pcall(value.func)
+        if status and res then
+          ev, idx = events.WATCH, index
+          stop = true
+          break
+        end
+      end
+      if stop then break end
+      if (step_into)
+      or (step_over and (stack_level[current_thread] <= step_level[current_thread] or stack_level[current_thread] == 0)) then
+        step_lines = step_lines - 1
+        if step_lines < 1 then
+          ev, idx = events.STEP, 0
+          break
+        end
+      end
+      if has_breakpoint(file, line) then
+        ev, idx = events.BREAK, 0
+        break
+      end
+      return
+    end
+    tracestack(level)
+    local last_next = 1
+    local err, next = assert(coroutine.resume(coro_debugger, ev, vars, file, line, idx))
+    while true do
+      if next == 'cont' then
+        return
+      elseif next == 'stop' then
+        started = false
+        debug.sethook()
+        return
+      elseif tonumber(next) then --get vars for given level or last level
+        next = tonumber(next)
+        if next == 0 then next = last_next end
+        last_next = next
+        restore_vars(level,vars)
+        vars, file, line = capture_vars(level,next)
+        err, next = assert(coroutine.resume(coro_debugger, events.SET, vars, file, line, idx))
+      else
+        io.write('Unknown command from debugger_loop: '..tostring(next)..'\n')
+        io.write('Stopping debugger\n')
+        next = 'stop'
+      end
+    end
+  end
+end
+
+--}}}
+--{{{  local function report(ev, vars, file, line, idx_watch)
+
+local function report(ev, vars, file, line, idx_watch)
+  local vars = vars or {}
+  local file = file or '?'
+  local line = line or 0
+  local prefix = ''
+  if current_thread ~= 'main' then prefix = '['..tostring(current_thread)..'] ' end
+  if ev == events.STEP then
+    io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..')\n')
+  elseif ev == events.BREAK then
+    io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..') (breakpoint)\n')
+  elseif ev == events.WATCH then
+    io.write(prefix.."Paused at file "..file.." line "..line..' ('..stack_level[current_thread]..')'.." (watch expression "..idx_watch.. ": ["..watches[idx_watch].exp.."])\n")
+  elseif ev == events.SET then
+    --do nothing
+  else
+    io.write(prefix.."Error in application: "..file.." line "..line.."\n")
+  end
+  if ev ~= events.SET then
+    if pausemsg and pausemsg ~= '' then io.write('Message: '..pausemsg..'\n') end
+    pausemsg = ''
+  end
+  return vars, file, line
+end
+
+--}}}
+
+--{{{  local function debugger_loop(server)
+
+local function debugger_loop(ev, vars, file, line, idx_watch)
+
+  io.write("Lua Debugger\n")
+  local eval_env, breakfile, breakline = report(ev, vars, file, line, idx_watch)
+  io.write("Type 'help' for commands\n")
+
+  local command, args
+
+  --{{{  local function getargs(spec)
+  
+  --get command arguments according to the given spec from the args string
+  --the spec has a single character for each argument, arguments are separated
+  --by white space, the spec characters can be one of:
+  -- F for a filename    (defaults to breakfile if - given in args)
+  -- L for a line number (defaults to breakline if - given in args)
+  -- N for a number
+  -- V for a variable name
+  -- S for a string
+  
+  local function getargs(spec)
+    local res={}
+    local char,arg
+    local ptr=1
+    for i=1,string.len(spec) do
+      char = string.sub(spec,i,i)
+      if     char == 'F' then
+        _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
+        if not arg or arg == '' then arg = '-' end
+        if arg == '-' then arg = breakfile end
+      elseif char == 'L' then
+        _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
+        if not arg or arg == '' then arg = '-' end
+        if arg == '-' then arg = breakline end
+        arg = tonumber(arg) or 0
+      elseif char == 'N' then
+        _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
+        if not arg or arg == '' then arg = '0' end
+        arg = tonumber(arg) or 0
+      elseif char == 'V' then
+        _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
+        if not arg or arg == '' then arg = '' end
+      elseif char == 'S' then
+        _,ptr,arg = string.find(args..' ',"%s*([%w%p]*)%s*",ptr)
+        if not arg or arg == '' then arg = '' end
+      else
+        arg = ''
+      end
+      table.insert(res,arg or '')
+    end
+    return unpack(res)
+  end
+  
+  --}}}
+
+  while true do
+    io.write("[DEBUG]> ")
+    local line = io.read("*line")
+    if line == nil then io.write('\n'); line = 'exit' end
+
+    if string.find(line, "^[a-z]+") then
+      command = string.sub(line, string.find(line, "^[a-z]+"))
+      args    = string.gsub(line,"^[a-z]+%s*",'',1)            --strip command off line
+    else
+      command = ''
+    end
+
+    if command == "setb" then
+      --{{{  set breakpoint
+      
+      local line, filename  = getargs('LF')
+      if filename ~= '' and line ~= '' then
+        set_breakpoint(filename,line)
+        io.write("Breakpoint set in file "..filename..' line '..line..'\n')
+      else
+        io.write("Bad request\n")
+      end
+      
+      --}}}
+
+    elseif command == "delb" then
+      --{{{  delete breakpoint
+      
+      local line, filename = getargs('LF')
+      if filename ~= '' and line ~= '' then
+        remove_breakpoint(filename, line)
+        io.write("Breakpoint deleted from file "..filename..' line '..line.."\n")
+      else
+        io.write("Bad request\n")
+      end
+      
+      --}}}
+
+    elseif command == "delallb" then
+      --{{{  delete all breakpoints
+      breakpoints = {}
+      io.write('All breakpoints deleted\n')
+      --}}}
+
+    elseif command == "listb" then
+      --{{{  list breakpoints
+      for i, v in pairs(breakpoints) do
+        for ii, vv in pairs(v) do
+          io.write("Break at: "..i..' in '..ii..'\n')
+        end
+      end
+      --}}}
+
+    elseif command == "setw" then
+      --{{{  set watch expression
+      
+      if args and args ~= '' then
+        local func = loadstring("return(" .. args .. ")")
+        local newidx = #watches + 1
+        watches[newidx] = {func = func, exp = args}
+        io.write("Set watch exp no. " .. newidx..'\n')
+      else
+        io.write("Bad request\n")
+      end
+      
+      --}}}
+
+    elseif command == "delw" then
+      --{{{  delete watch expression
+      
+      local index = tonumber(args)
+      if index then
+        watches[index] = nil
+        io.write("Watch expression deleted\n")
+      else
+        io.write("Bad request\n")
+      end
+      
+      --}}}
+
+    elseif command == "delallw" then
+      --{{{  delete all watch expressions
+      watches = {}
+      io.write('All watch expressions deleted\n')
+      --}}}
+
+    elseif command == "listw" then
+      --{{{  list watch expressions
+      for i, v in pairs(watches) do
+        io.write("Watch exp. " .. i .. ": " .. v.exp..'\n')
+      end
+      --}}}
+
+    elseif command == "run" then
+      --{{{  run until breakpoint
+      step_into = false
+      step_over = false
+      eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+      --}}}
+
+    elseif command == "step" then
+      --{{{  step N lines (into functions)
+      local N = tonumber(args) or 1
+      step_over  = false
+      step_into  = true
+      step_lines = tonumber(N or 1)
+      eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+      --}}}
+
+    elseif command == "over" then
+      --{{{  step N lines (over functions)
+      local N = tonumber(args) or 1
+      step_into  = false
+      step_over  = true
+      step_lines = tonumber(N or 1)
+      step_level[current_thread] = stack_level[current_thread]
+      eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+      --}}}
+
+    elseif command == "out" then
+      --{{{  step N lines (out of functions)
+      local N = tonumber(args) or 1
+      step_into  = false
+      step_over  = true
+      step_lines = 1
+      step_level[current_thread] = stack_level[current_thread] - tonumber(N or 1)
+      eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+      --}}}
+
+    elseif command == "goto" then
+      --{{{  step until reach line
+      local N = tonumber(args)
+      if N then
+        step_over  = false
+        step_into  = false
+        if has_breakpoint(breakfile,N) then
+          eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+        else
+          local bf = breakfile
+          set_breakpoint(breakfile,N)
+          eval_env, breakfile, breakline = report(coroutine.yield('cont'))
+          if breakfile == bf and breakline == N then remove_breakpoint(breakfile,N) end
+        end
+      else
+        io.write("Bad request\n")
+      end
+      --}}}
+
+    elseif command == "set" then
+      --{{{  set/show context level
+      local level = args
+      if level and level == '' then level = nil end
+      if level then
+        eval_env, breakfile, breakline = report(coroutine.yield(level))
+      end
+      if eval_env.__VARSLEVEL__ then
+        io.write('Level: '..eval_env.__VARSLEVEL__..'\n')
+      else
+        io.write('No level set\n')
+      end
+      --}}}
+
+    elseif command == "vars" then
+      --{{{  list context variables
+      local depth = args
+      if depth and depth == '' then depth = nil end
+      depth = tonumber(depth) or 1
+      dumpvar(eval_env, depth+1, 'variables')
+      --}}}
+
+    elseif command == "glob" then
+      --{{{  list global variables
+      local depth = args
+      if depth and depth == '' then depth = nil end
+      depth = tonumber(depth) or 1
+      dumpvar(eval_env.__GLOBALS__,depth+1,'globals')
+      --}}}
+
+    elseif command == "fenv" then
+      --{{{  list function environment variables
+      local depth = args
+      if depth and depth == '' then depth = nil end
+      depth = tonumber(depth) or 1
+      dumpvar(eval_env.__ENVIRONMENT__,depth+1,'environment')
+      --}}}
+
+    elseif command == "ups" then
+      --{{{  list upvalue names
+      dumpvar(eval_env.__UPVALUES__,2,'upvalues')
+      --}}}
+
+    elseif command == "locs" then
+      --{{{  list locals names
+      dumpvar(eval_env.__LOCALS__,2,'upvalues')
+      --}}}
+
+    elseif command == "what" then
+      --{{{  show where a function is defined
+      if args and args ~= '' then
+        local v = eval_env
+        local n = nil
+        for w in string.gmatch(args,"[%w_]+") do
+          v = v[w]
+          if n then n = n..'.'..w else n = w end
+          if not v then break end
+        end
+        if type(v) == 'function' then
+          local def = debug.getinfo(v,'S')
+          if def then
+            io.write(def.what..' in '..def.short_src..' '..def.linedefined..'..'..def.lastlinedefined..'\n')
+          else
+            io.write('Cannot get info for '..v..'\n')
+          end
+        else
+          io.write(v..' is not a function\n')
+        end
+      else
+        io.write("Bad request\n")
+      end
+      --}}}
+
+    elseif command == "dump" then
+      --{{{  dump a variable
+      local name, depth = getargs('VN')
+      if name ~= '' then
+        if depth == '' or depth == 0 then depth = nil end
+        depth = tonumber(depth or 1)
+        local v = eval_env
+        local n = nil
+        for w in string.gmatch(name,"[^%.]+") do     --get everything between dots
+          if tonumber(w) then
+            v = v[tonumber(w)]
+          else
+            v = v[w]
+          end
+          if n then n = n..'.'..w else n = w end
+          if not v then break end
+        end
+        dumpvar(v,depth+1,n)
+      else
+        io.write("Bad request\n")
+      end
+      --}}}
+
+    elseif command == "show" then
+      --{{{  show file around a line or the current breakpoint
+      
+      local line, file, before, after = getargs('LFNN')
+      if before == 0 then before = 10     end
+      if after  == 0 then after  = before end
+      
+      if file ~= '' and file ~= "=stdin" then
+        show(file,line,before,after)
+      else
+        io.write('Nothing to show\n')
+      end
+      
+      --}}}
+
+    elseif command == "poff" then
+      --{{{  turn pause command off
+      pause_off = true
+      --}}}
+
+    elseif command == "pon" then
+      --{{{  turn pause command on
+      pause_off = false
+      --}}}
+
+    elseif command == "tron" then
+      --{{{  turn tracing on/off
+      local option = getargs('S')
+      trace_calls   = false
+      trace_returns = false
+      trace_lines   = false
+      if string.find(option,'c') then trace_calls   = true end
+      if string.find(option,'r') then trace_returns = true end
+      if string.find(option,'l') then trace_lines   = true end
+      --}}}
+
+    elseif command == "trace" then
+      --{{{  dump a stack trace
+      trace(eval_env.__VARSLEVEL__)
+      --}}}
+
+    elseif command == "info" then
+      --{{{  dump all debug info captured
+      info()
+      --}}}
+
+    elseif command == "pause" then
+      --{{{  not allowed in here
+      io.write('pause() should only be used in the script you are debugging\n')
+      --}}}
+
+    elseif command == "help" then
+      --{{{  help
+      local command = getargs('S')
+      if command ~= '' and hints[command] then
+        io.write(hints[command]..'\n')
+      else
+        for _,v in pairs(hints) do
+          local _,_,h = string.find(v,"(.+)|")
+          io.write(h..'\n')
+        end
+      end
+      --}}}
+
+    elseif command == "exit" then
+      --{{{  exit debugger
+      return 'stop'
+      --}}}
+
+    elseif line ~= '' then
+      --{{{  just execute whatever it is in the current context
+      
+      --map line starting with "=..." to "return ..."
+      if string.sub(line,1,1) == '=' then line = string.gsub(line,'=','return ',1) end
+      
+      local ok, func = pcall(loadstring,line)
+      if func == nil then                             --Michael.Bringmann at lsi.com
+        io.write("Compile error: "..line..'\n')
+      elseif not ok then
+        io.write("Compile error: "..func..'\n')
+      else
+        setfenv(func, eval_env)
+        local res = {pcall(func)}
+        if res[1] then
+          if res[2] then
+            table.remove(res,1)
+            for _,v in ipairs(res) do
+              io.write(tostring(v))
+              io.write('\t')
+            end
+            io.write('\n')
+          end
+          --update in the context
+          eval_env, breakfile, breakline = report(coroutine.yield(0))
+        else
+          io.write("Run error: "..res[2]..'\n')
+        end
+      end
+      
+      --}}}
+    end
+  end
+
+end
+
+--}}}
+
+--{{{  coroutine.create
+
+--This function overrides the built-in for the purposes of propagating
+--the debug hook settings from the creator into the created coroutine.
+
+_G.coroutine.create = function(f)
+  local thread
+  local hook, mask, count = debug.gethook()
+  if hook then
+    local function thread_hook(event,line)
+      hook(event,line,3,thread)
+    end
+    thread = cocreate(function(...)
+                        stack_level[thread] = 0
+                        trace_level[thread] = 0
+                        step_level [thread] = 0
+                        debug.sethook(thread_hook,mask,count)
+                        return f(...)
+                      end)
+    return thread
+  else
+    return cocreate(f)
+  end
+end
+
+--}}}
+--{{{  coroutine.wrap
+
+--This function overrides the built-in for the purposes of propagating
+--the debug hook settings from the creator into the created coroutine.
+
+_G.coroutine.wrap = function(f)
+  local thread
+  local hook, mask, count = debug.gethook()
+  if hook then
+    local function thread_hook(event,line)
+      hook(event,line,3,thread)
+    end
+    thread = cowrap(function(...)
+                      stack_level[thread] = 0
+                      trace_level[thread] = 0
+                      step_level [thread] = 0
+                      debug.sethook(thread_hook,mask,count)
+                      return f(...)
+                    end)
+    return thread
+  else
+    return cowrap(f)
+  end
+end
+
+--}}}
+
+--{{{  function pause()
+
+--
+-- Starts/resumes a debug session
+--
+
+function pause(x)
+  if pause_off then return end               --being told to ignore pauses
+  pausemsg = x or 'pause'
+  local lines
+  local src = getinfo(2,'short_src')
+  if src == "stdin" then
+    lines = 1   --if in a console session, stop now
+  else
+    lines = 2   --if in a script, stop when get out of pause()
+  end
+  if started then
+    --we'll stop now 'cos the existing debug hook will grab us
+    step_lines = lines
+    step_into  = true
+  else
+    coro_debugger = cocreate(debugger_loop)  --NB: Use original coroutune.create
+    --set to stop when get out of pause()
+    trace_level[current_thread] = 0
+    step_level [current_thread] = 0
+    stack_level[current_thread] = 1
+    step_lines = lines
+    step_into  = true
+    started    = true
+    debug.sethook(debug_hook, "crl")         --NB: this will cause an immediate entry to the debugger_loop
+  end
+end
+
+--}}}
+--{{{  function dump()
+
+--shows the value of the given variable, only really useful
+--when the variable is a table
+--see dump debug command hints for full semantics
+
+function dump(v,depth)
+  dumpvar(v,(depth or 1)+1,tostring(v))
+end
+
+--}}}
+--{{{  function debug.traceback(x)
+
+local _traceback = debug.traceback       --note original function
+
+--override standard function
+debug.traceback = function(x)
+  local assertmsg = _traceback(x)        --do original function
+  pause(x)                               --let user have a look at stuff
+  return assertmsg                       --carry on
+end
+
+_TRACEBACK = debug.traceback             --Lua 5.0 function
+
+--}}}
+

Modified: code/branches/gamestates2/data/lua/LuaStateInit.lua
===================================================================
--- code/branches/gamestates2/data/lua/LuaStateInit.lua	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/data/lua/LuaStateInit.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -1,9 +1,7 @@
 -- Note: luaState is a pointer to the LuaState instance that created this lua state
 
--- Save original print function in debug
-debug = print
-
 -- Redirect print to the C++ print function
+original_print = print
 print = function(s)
   luaState:luaPrint(s)
 end
@@ -12,47 +10,88 @@
 logMessage = function(level, message)
   luaState:luaLog(level, message)
 end
+cout = logMessage
 
 -- Redirect dofile in order to load with the resource manager
-doFile = function(filename)
+original_dofile = dofile
+dofile = function(filename)
   luaState:doFile(filename)
-  -- Required because the C++ function cannot return whatever might be on the stack
+  -- Required because if the file returns a table, it cannot be passed through the C++ function
   return LuaStateReturnValue -- C-injected global variable
 end
-original_dofile = dofile
-dofile = doFile
+doFile = dofile
 
 -- Create includeFile function that preparses the file according
 -- to a function provided to the LuaState constructor (in C++)
 include = function(filename)
   luaState:includeFile(filename)
-  -- Required because the C++ function cannot return whatever might be on the stack
+  -- Required because if the file returns a table, it cannot be passed through the C++ function
   return LuaStateReturnValue -- C-injected global variable
 end
 
 -- Replace require function with almost similar behaviour
 -- The loaded modules are then stored with their names (where name has no .lua extension)
 -- Furthermore the ".lua" extension is appended to the moduleName parameter when looking for the file
-old_require = require
+original_require = require
+_REQUIREDNAME = ""
+LuaStateReturnValue = true
 require = function(moduleName)
   if not luaState:fileExists(moduleName .. ".lua") then
+    logMessage(2, "Warning: Lua function require() could not find file '" .. moduleName .. ".lua' ")
     return nil
   end
   if not _LOADED then
     _LOADED = {}
   end
-  if not _LOADED[moduleName] then
+  if _LOADED[moduleName] == nil then
     -- save old value
-    _REQUIREDNAME_OLD = _REQUIREDNAME
+    local _REQUIREDNAME_OLD = _REQUIREDNAME
     _REQUIREDNAME = moduleName
     luaState:doFile(moduleName .. ".lua")
-    _LOADED[moduleName] = LuaStateReturnValue or true
+    -- LuaStateReturnValue is required because if the file returns a table,
+    -- it cannot be passed through the C++ function
+    if LuaStateReturnValue == nil then -- C-injected global variable
+        LuaStateReturnValue = true
+    end
+    _LOADED[moduleName] = LuaStateReturnValue -- This entry must never be nil
     -- restore old value
     _REQUIREDNAME = _REQUIREDNAME_OLD
   end
   return _LOADED[moduleName]
 end
 
+
+-- Include command line debugger for lua 5.1
+-- Note: It doesn't work if the IOConsole was started. Then we replace pause() with a warning
+if _VERSION ~= "Lua 5.0"  and not luaState:usingIOConsole() then
+  require("Debugger")
+else
+  -- Fallback pause function
+  pause = function()
+    logMessage(2, [["Warning: debug() called in Lua, but Debugger is not active.
+Do you have the IOConsole disabled and are you using Lua version 5.1?"]])
+  end
+end
+
+-- General error handler that gets called whenever an error happens at runtime
+errorHandler = function(err)
+  -- Display the error message
+  if type(err) == "string" then
+    logMessage(1, "Lua runtime error: "..err)
+  end
+
+  -- Start debugger if possible
+  if _LOADED and _LOADED["Debugger"] ~= nil then
+    pause()
+  else
+    -- Fallback: print stack trace
+    logMessage(1, debug.traceback(2))
+  end
+  return err -- Hello Lua debugger user! Please type 'set 2' to get to the
+             -- actual position in the stack where the error occurred
+end
+
+
 -- Convenience function for console commands
 orxonox.execute = function(command)
   orxonox.CommandExecutor:execute(command)

Copied: code/branches/gamestates2/data/lua/Strict.lua (from rev 6661, code/branches/gamestate/data/lua/Strict.lua)
===================================================================
--- code/branches/gamestates2/data/lua/Strict.lua	                        (rev 0)
+++ code/branches/gamestates2/data/lua/Strict.lua	2010-03-30 23:05:28 UTC (rev 6662)
@@ -0,0 +1,39 @@
+--
+-- strict.lua
+-- checks uses of undeclared global variables
+-- All global variables must be 'declared' through a regular assignment
+-- (even assigning nil will do) in a main chunk before being used
+-- anywhere or assigned to inside a function.
+--
+
+local mt = getmetatable(_G)
+if mt == nil then
+  mt = {}
+  setmetatable(_G, mt)
+end
+
+__STRICT = false
+mt.__declared = {}
+
+mt.__newindex = function (t, n, v)
+  if __STRICT and not mt.__declared[n] then
+    local d = debug.getinfo(2, "S")
+    local w = d and d.what or "C"
+    if w ~= "main" and w ~= "C" then
+      error("assign to undeclared variable '"..n.."'", 2)
+    end
+    mt.__declared[n] = true
+  end
+  rawset(t, n, v)
+end
+  
+mt.__index = function (t, n)
+  if not mt.__declared[n] and debug.getinfo(2, "S").what ~= "C" then
+    error("variable '"..n.."' is not declared", 2)
+  end
+  return rawget(t, n)
+end
+
+function global(...)
+   for _, v in ipairs{...} do mt.__declared[v] = true end
+end

Modified: code/branches/gamestates2/src/libraries/core/Core.cc
===================================================================
--- code/branches/gamestates2/src/libraries/core/Core.cc	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/Core.cc	2010-03-30 23:05:28 UTC (rev 6662)
@@ -77,6 +77,7 @@
     Core* Core::singletonPtr_s  = 0;
 
     SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
+    SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
 #ifdef ORXONOX_PLATFORM_WINDOWS
     SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
 #endif
@@ -87,6 +88,7 @@
         // Cleanup guard for external console commands that don't belong to an Identifier
         , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
         , bGraphicsLoaded_(false)
+        , bStartIOConsole_(true)
     {
         // Set the hard coded fixed paths
         this->pathConfig_.reset(new PathConfig());
@@ -148,7 +150,12 @@
         this->setConfigValues();
 
         // create persistent io console
-        this->ioConsole_.reset(new IOConsole());
+        if (CommandLineParser::getValue("noIOConsole").getBool())
+        {
+            ModifyConfigValue(bStartIOConsole_, tset, false);
+        }
+        if (this->bStartIOConsole_)
+            this->ioConsole_.reset(new IOConsole());
 
         // creates the class hierarchy for all classes with factories
         Identifier::createClassHierarchy();
@@ -192,6 +199,8 @@
         SetConfigValue(bInitRandomNumberGenerator_, true)
             .description("If true, all random actions are different each time you start the game")
             .callback(this, &Core::initRandomNumberGenerator);
+        SetConfigValue(bStartIOConsole_, true)
+            .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)");
     }
 
     //! Callback function if the language has changed.
@@ -326,7 +335,8 @@
             ScopedSingletonManager::preUpdate<ScopeID::Graphics>(time);
         }
         // Process console events and status line
-        this->ioConsole_->preUpdate(time);
+        if (this->ioConsole_ != NULL)
+            this->ioConsole_->preUpdate(time);
         // Process thread commands
         this->tclThreadManager_->preUpdate(time);
     }

Modified: code/branches/gamestates2/src/libraries/core/Core.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/Core.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/Core.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -96,7 +96,7 @@
             scoped_ptr<IOConsole>         ioConsole_;
             scoped_ptr<TclBind>           tclBind_;
             scoped_ptr<TclThreadManager>  tclThreadManager_;
-            scoped_ptr<Scope<ScopeID::Root> >     rootScope_;
+            scoped_ptr<Scope<ScopeID::Root> > rootScope_;
             // graphical
             scoped_ptr<GraphicsManager>   graphicsManager_;     //!< Interface to OGRE
             scoped_ptr<InputManager>      inputManager_;        //!< Interface to OIS
@@ -107,6 +107,7 @@
             int                           softDebugLevelLogFile_;      //!< The debug level for the log file (belongs to OutputHandler)
             std::string                   language_;                   //!< The language
             bool                          bInitRandomNumberGenerator_; //!< If true, srand(time(0)) is called
+            bool                          bStartIOConsole_;            //!< Set to false if you don't want to use the IOConsole
 
             static Core*                  singletonPtr_s;
     };

Modified: code/branches/gamestates2/src/libraries/core/GUIManager.cc
===================================================================
--- code/branches/gamestates2/src/libraries/core/GUIManager.cc	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/GUIManager.cc	2010-03-30 23:05:28 UTC (rev 6662)
@@ -252,19 +252,27 @@
         GUIManager::getInstance().executeCode("hideGUI(\"" + name + "\")");
     }
 
-    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showMouse, TriBool::Value useKeyboard, bool bBlockJoyStick)
+    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
     {
         InputState* state = InputManager::getInstance().createInputState(name);
 
-        if (GraphicsManager::getInstance().isFullScreen() && showMouse == TriBool::True ||
-           !GraphicsManager::getInstance().isFullScreen() && showMouse == TriBool::False)
+        /* Table that maps isFullScreen() and showCursor to mouseExclusive
+        isFullscreen / showCursor | True  | False | Dontcare
+        ----------------------------------------------------
+        true                      | True  | True  | Dontcare
+        ----------------------------------------------------
+        false                     | False | True  | Dontcare
+        */
+        if (showCursor == TriBool::Dontcare)
+            state->setMouseExclusive(TriBool::Dontcare);
+        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
             state->setMouseExclusive(TriBool::True);
         else
-            state->setMouseExclusive(TriBool::Dontcare);
+            state->setMouseExclusive(TriBool::False);
 
-        if (showMouse == TriBool::True)
+        if (showCursor == TriBool::True)
             state->setMouseHandler(this);
-        else if (showMouse == TriBool::False)
+        else if (showCursor == TriBool::False)
             state->setMouseHandler(&InputHandler::EMPTY);
 
         if (useKeyboard == TriBool::True)

Modified: code/branches/gamestates2/src/libraries/core/GUIManager.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/GUIManager.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/GUIManager.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -80,7 +80,7 @@
         void keyESC();
         void setBackground(const std::string& name);
 
-        const std::string& createInputState(const std::string& name, TriBool::Value showMouse = TriBool::True, TriBool::Value useKeyboard = TriBool::True, bool bBlockJoyStick = false); // tolua_export
+        const std::string& createInputState(const std::string& name, TriBool::Value showCursor = TriBool::True, TriBool::Value useKeyboard = TriBool::True, bool bBlockJoyStick = false); // tolua_export
 
         void setCamera(Ogre::Camera* camera);
         Ogre::Camera* getCamera() { return this->camera_; }

Modified: code/branches/gamestates2/src/libraries/core/LuaState.cc
===================================================================
--- code/branches/gamestates2/src/libraries/core/LuaState.cc	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/LuaState.cc	2010-03-30 23:05:28 UTC (rev 6662)
@@ -36,6 +36,9 @@
 }
 
 #include "util/Debug.h"
+#include "util/Exception.h"
+#include "util/ScopeGuard.h"
+#include "IOConsole.h"
 #include "Resource.h"
 #include "ToluaBindCore.h"
 
@@ -53,6 +56,7 @@
     {
         // Create new lua state and configure it
         luaState_ = lua_open();
+        Loki::ScopeGuard luaStateGuard = Loki::MakeGuard(&lua_close, luaState_);
 #if LUA_VERSION_NUM == 501
         luaL_openlibs(luaState_);
 #else
@@ -77,7 +81,10 @@
         lua_setglobal(luaState_, "luaState");
 
         // Parse init script
-        this->doFile("LuaStateInit.lua");
+        if (!this->doFile("LuaStateInit.lua"))
+            ThrowException(InitialisationFailed, "Running LuaStateInit.lua failed");
+
+        luaStateGuard.Dismiss();
     }
 
     LuaState::~LuaState()
@@ -95,16 +102,19 @@
         return sourceInfo;
     }
 
-    void LuaState::includeFile(const std::string& filename)
+    bool LuaState::includeFile(const std::string& filename)
     {
         shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
         if (sourceInfo != NULL)
-            this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
+            return this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
         else
-            COUT(2) << "LuaState: Cannot include file '" << filename << "'." << std::endl;
+        {
+            COUT(2) << "LuaState: Cannot include file '" << filename << "' (not found)." << std::endl;
+            return false;
+        }
     }
 
-    void LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
+    bool LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     {
         // Parse string with provided include parser (otherwise don't preparse at all)
         std::string luaInput;
@@ -113,19 +123,38 @@
         else
             luaInput = code;
 
-        this->doString(luaInput, sourceFileInfo);
+        if (sourceFileInfo != NULL)
+        {
+            // Also fill a map with the actual source code. This is just for the include* commands
+            // where the content of sourceFileInfo->filename doesn't match 'code'
+            this->sourceCodeMap_[sourceFileInfo->filename] = code;
+        }
+
+        bool returnValue = this->doString(luaInput, sourceFileInfo);
+
+        if (sourceFileInfo != NULL)
+        {
+            // Delete source code entry
+            if (sourceFileInfo != NULL)
+                this->sourceCodeMap_.erase(sourceFileInfo->filename);
+        }
+
+        return returnValue;
     }
 
-    void LuaState::doFile(const std::string& filename)
+    bool LuaState::doFile(const std::string& filename)
     {
         shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
         if (sourceInfo != NULL)
-            this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
+            return this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
         else
-            COUT(2) << "LuaState: Cannot do file '" << filename << "'." << std::endl;
+        {
+            COUT(2) << "LuaState: Cannot do file '" << filename << "' (not found)." << std::endl;
+            return false;
+        }
     }
 
-    void LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
+    bool LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     {
         // Save the old source file info
         shared_ptr<ResourceInfo> oldSourceFileInfo = sourceFileInfo_;
@@ -133,33 +162,84 @@
         if (sourceFileInfo != NULL)
             sourceFileInfo_ = sourceFileInfo;
 
-        int error = 0;
+        std::string chunkname;
+        if (sourceFileInfo != NULL)
+        {
+            // Provide lua_load with the filename for debug purposes
+            // The '@' is a Lua convention to identify the chunk name as filename
+            chunkname = '@' + sourceFileInfo->filename;
+        }
+        else
+        {
+            // Use the code string to identify the chunk
+            chunkname = code;
+        }
+
+        // Push custom error handler that uses the debugger
+        int errorHandler = 1;
+        lua_getglobal(this->luaState_, "errorHandler");
+        if (lua_isnil(this->luaState_, -1))
+        {
+            lua_pop(this->luaState_, 1);
+            errorHandler = 0;
+        }
+
 #if LUA_VERSION_NUM != 501
         LoadS ls;
         ls.s = code.c_str();
         ls.size = code.size();
-        error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, code.c_str());
+        int error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, chunkname.c_str());
 #else
-        error = luaL_loadstring(luaState_, code.c_str());
+        int error = luaL_loadbuffer(luaState_, code.c_str(), code.size(), chunkname.c_str());
 #endif
 
-        // execute the chunk
+        switch (error)
+        {
+        case LUA_ERRSYNTAX: // Syntax error
+            COUT(1) << "Lua syntax error: " << lua_tostring(luaState_, -1) << std::endl;
+            break;
+        case LUA_ERRMEM:    // Memory allocation error
+            COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
+            lua_pop(luaState_, 1);
+            break;
+        }
+
         if (error == 0)
-            error = lua_pcall(luaState_, 0, 1, 0);
+        {
+            // Execute the chunk in protected mode with an error handler function (stack index)
+            error = lua_pcall(luaState_, 0, 1, errorHandler);
+
+            switch (error)
+            {
+            case LUA_ERRRUN: // Runtime error
+                // Remove error string from stack (we already display the error in the
+                // 'errorHandler' Lua function in LuaStateInit.lua)
+                lua_pop(luaState_, 1);
+                break;
+            case LUA_ERRERR: // Error in the error handler
+                COUT(1) << "Lua error in error handler: " << lua_tostring(luaState_, -1) << std::endl;
+                break;
+            case LUA_ERRMEM: // Memory allocation error
+                COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
+                lua_pop(luaState_, 1);
+                break;
+            }
+        }
+
         if (error != 0)
         {
-            std::string origin;
-            if (sourceFileInfo != NULL)
-                origin = " originating from " + sourceFileInfo_->filename;
-            COUT(1) << "Error in Lua-script" << origin << ": " << lua_tostring(luaState_, -1) << std::endl;
-            // return value is nil
+            // Push a nil return value
             lua_pushnil(luaState_);
         }
-        // push return value because it will get lost since the return value of this function is void
+
+        // Set return value to a global variable because we cannot return a table in this function
+        // here. It would work for numbers, pointers and strings, but certainly not for Lua tables.
         lua_setglobal(luaState_, "LuaStateReturnValue");
 
         // Load the old info again
         sourceFileInfo_ = oldSourceFileInfo;
+
+        return (error == 0);
     }
 
     void LuaState::luaPrint(const std::string& str)
@@ -181,6 +261,26 @@
             return true;
     }
 
+    //! Returns the content of a file
+    std::string LuaState::getSourceCode(const std::string& filename)
+    {
+        // Try the internal map first to get the actual Lua code
+        // and not just some pseudo Lua-XML code when using include* commands
+        std::map<std::string, std::string>::const_iterator it = this->sourceCodeMap_.find(filename);
+        if (it != this->sourceCodeMap_.end())
+            return it->second;
+        shared_ptr<ResourceInfo> info = Resource::getInfo(filename);
+        if (info == NULL)
+            return "";
+        else
+            return Resource::open(info)->getAsString();
+    }
+
+    bool LuaState::usingIOConsole() const
+    {
+        return IOConsole::exists();
+    }
+
 #if LUA_VERSION_NUM != 501
     const char * LuaState::lua_Chunkreader(lua_State *L, void *data, size_t *size)
     {

Modified: code/branches/gamestates2/src/libraries/core/LuaState.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/LuaState.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/LuaState.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -70,15 +70,16 @@
         LuaState();
         ~LuaState();
 
-        void doFile(const std::string& filename); // tolua_export
-        void doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
+        bool doFile(const std::string& filename); // tolua_export
+        bool doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
 
-        void includeFile(const std::string& filename); // tolua_export
-        void includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
+        bool includeFile(const std::string& filename); // tolua_export
+        bool includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
 
         void luaPrint(const std::string& str); // tolua_export
         void luaLog(unsigned int level, const std::string& message); // tolua_export
         bool fileExists(const std::string& filename); // tolua_export
+        std::string getSourceCode(const std::string& filename); // tolua_export
 
         const std::stringstream& getOutput() const { return output_; }
         void clearOutput() { output_.clear(); } // tolua_export
@@ -90,6 +91,8 @@
         const shared_ptr<ResourceInfo>& getDefaultResourceInfo() { return this->sourceFileInfo_; }
 
         Functor* createLuaFunctor(const std::string& code) { return new LuaFunctor(code, this); } // tolua_export
+        //! Tells about whether IOConsole was activated. The Lua debugger only works with a normal console.
+        bool usingIOConsole() const; // tolua_export
 
         static bool addToluaInterface(int (*function)(lua_State*), const std::string& name);
         static bool removeToluaInterface(const std::string& name);
@@ -113,6 +116,7 @@
         lua_State* luaState_;
         bool bIsRunning_;
         shared_ptr<ResourceInfo> sourceFileInfo_;
+        std::map<std::string, std::string> sourceCodeMap_;
         std::string (*includeParseFunction_)(const std::string&);
 
         typedef std::map<std::string, int (*)(lua_State *L)> ToluaInterfaceMap;

Modified: code/branches/gamestates2/src/libraries/core/Resource.cc
===================================================================
--- code/branches/gamestates2/src/libraries/core/Resource.cc	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/Resource.cc	2010-03-30 23:05:28 UTC (rev 6662)
@@ -28,7 +28,9 @@
 
 #include "Resource.h"
 
+#include <boost/filesystem/path.hpp>
 #include <OgreException.h>
+#include <OgreFileSystem.h>
 #include <OgreResourceGroupManager.h>
 
 namespace orxonox
@@ -88,6 +90,12 @@
                 ptr->basename = it->basename;
                 ptr->group = group;
                 ptr->size = it->uncompressedSize;
+                if (dynamic_cast<Ogre::FileSystemArchive*>(it->archive) != NULL)
+                {
+                    boost::filesystem::path base(it->archive->getName());
+                    base /= it->filename;
+                    ptr->fileSystemPath = base.string();
+                }
                 return ptr;
             }
         }

Modified: code/branches/gamestates2/src/libraries/core/Resource.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/Resource.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/Resource.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -56,6 +56,8 @@
         std::string group;
         //! Uncompressed size
         size_t size;
+        //! Absolute file path ("" for files not on filesystem)
+        std::string fileSystemPath;
     };
 
     /** Provides simple functions to easily access the Ogre::ResourceGroupManager.

Modified: code/branches/gamestates2/src/libraries/core/input/InputDevice.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputDevice.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputDevice.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -158,7 +158,7 @@
             // Call all the states with the held button event
             for (unsigned int iB = 0; iB < pressedButtons_.size(); ++iB)
                 for (unsigned int iS = 0; iS < inputStates_.size(); ++iS)
-                    inputStates_[iS]->buttonEvent<ButtonEvent::THold, Traits>(
+                    inputStates_[iS]->buttonEvent<ButtonEvent::THold, Traits::ButtonTypeParam>(
                         this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(pressedButtons_[iB]));
 
             // Call states with device update events
@@ -195,7 +195,7 @@
 
             // Call states
             for (unsigned int i = 0; i < inputStates_.size(); ++i)
-                inputStates_[i]->buttonEvent<ButtonEvent::TPress, Traits>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
+                inputStates_[i]->buttonEvent<ButtonEvent::TPress, Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
         }
 
         //! Common code for all button released events (updates pressed buttons list and calls the input states)
@@ -217,7 +217,7 @@
 
             // Call states
             for (unsigned int i = 0; i < inputStates_.size(); ++i)
-                inputStates_[i]->buttonEvent<ButtonEvent::TRelease, Traits>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
+                inputStates_[i]->buttonEvent<ButtonEvent::TRelease, Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
         }
 
         //! Managed pointer to the OIS device

Modified: code/branches/gamestates2/src/libraries/core/input/InputHandler.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputHandler.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputHandler.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -111,17 +111,17 @@
     public:
         virtual ~InputHandler() { }
 
-        template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::TPress)
+        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::TPress)
             { this->buttonPressed(button); }
-        template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::TRelease)
+        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::TRelease)
             { this->buttonReleased(button); }
-        template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::THold)
+        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::THold)
             { this->buttonHeld(button); }
-        void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TPress)
+        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TPress)
             { this->buttonPressed(device - InputDeviceEnumerator::FirstJoyStick, button); }
-        void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TRelease)
+        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TRelease)
             { this->buttonReleased(device - InputDeviceEnumerator::FirstJoyStick, button); }
-        void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::THold)
+        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::THold)
             { this->buttonHeld(device - InputDeviceEnumerator::FirstJoyStick, button); }
 
         virtual void buttonPressed (const KeyEvent& evt) { }

Modified: code/branches/gamestates2/src/libraries/core/input/InputManager.cc
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputManager.cc	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputManager.cc	2010-03-30 23:05:28 UTC (rev 6662)
@@ -94,6 +94,9 @@
 
         CCOUT(4) << "Constructing..." << std::endl;
 
+        // Allocate space for the function call buffer
+        this->callBuffer_.reserve(16);
+
         this->setConfigValues();
 
         if (GraphicsManager::getInstance().isFullScreen())
@@ -265,14 +268,19 @@
     {
         CCOUT(3) << "Destroying..." << std::endl;
 
+        // Leave all active InputStates (except "empty")
+        while (this->activeStates_.size() > 1)
+            this->leaveState(this->activeStates_.rbegin()->second->getName());
+        this->activeStates_.clear();
+
         // Destroy calibrator helper handler and state
         this->destroyState("calibrator");
         // Destroy KeyDetector and state
         calibratorCallbackHandler_->destroy();
-        // destroy the empty InputState
+        // Destroy the empty InputState
         this->destroyStateInternal(this->emptyState_);
 
-        // destroy all user InputStates
+        // Destroy all user InputStates
         while (statesByName_.size() > 0)
             this->destroyStateInternal(statesByName_.rbegin()->second);
 
@@ -334,14 +342,7 @@
 
     void InputManager::reload()
     {
-        if (internalState_ & Ticking)
-        {
-            // We cannot destroy OIS right now, because reload was probably
-            // caused by a user clicking on a GUI item. The stack trace would then
-            // include an OIS method. So it would be a very bad thing to destroy it..
-            internalState_ |= ReloadRequest;
-        }
-        else if (internalState_ & Calibrating)
+        if (internalState_ & Calibrating)
             CCOUT(2) << "Warning: Cannot reload input system. Joy sticks are currently being calibrated." << std::endl;
         else
             reloadInternal();
@@ -350,13 +351,12 @@
     //! Internal reload method. Destroys the OIS devices and loads them again.
     void InputManager::reloadInternal()
     {
-        CCOUT(3) << "Reloading ..." << std::endl;
+        CCOUT(4) << "Reloading ..." << std::endl;
 
         this->destroyDevices();
         this->loadDevices();
 
         internalState_ &= ~Bad;
-        internalState_ &= ~ReloadRequest;
         CCOUT(4) << "Reloading complete." << std::endl;
     }
 
@@ -370,70 +370,6 @@
         if (internalState_ & Bad)
             ThrowException(General, "InputManager was not correctly reloaded.");
 
-        else if (internalState_ & ReloadRequest)
-            reloadInternal();
-
-        // check for states to leave
-        if (!stateLeaveRequests_.empty())
-        {
-            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
-                it != stateLeaveRequests_.end(); ++it)
-            {
-                (*it)->left();
-                // just to be sure that the state actually is registered
-                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
-
-                activeStates_.erase((*it)->getPriority());
-                if ((*it)->getPriority() < InputStatePriority::HighPriority)
-                    (*it)->setPriority(0);
-                updateActiveStates();
-            }
-            stateLeaveRequests_.clear();
-        }
-
-        // check for states to enter
-        if (!stateEnterRequests_.empty())
-        {
-            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
-                it != stateEnterRequests_.end(); ++it)
-            {
-                // just to be sure that the state actually is registered
-                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
-
-                if ((*it)->getPriority() == 0)
-                {
-                    // Get smallest possible priority between 1 and maxStateStackSize_s
-                    for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
-                        rit != activeStates_.rend(); ++rit)
-                    {
-                        if (rit->first < InputStatePriority::HighPriority)
-                        {
-                            (*it)->setPriority(rit->first + 1);
-                            break;
-                        }
-                    }
-                    // In case no normal handler was on the stack
-                    if ((*it)->getPriority() == 0)
-                        (*it)->setPriority(1);
-                }
-                activeStates_[(*it)->getPriority()] = (*it);
-                updateActiveStates();
-                (*it)->entered();
-            }
-            stateEnterRequests_.clear();
-        }
-
-        // check for states to destroy
-        if (!stateDestroyRequests_.empty())
-        {
-            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
-                it != stateDestroyRequests_.end(); ++it)
-            {
-                destroyStateInternal((*it));
-            }
-            stateDestroyRequests_.clear();
-        }
-
         // check whether a state has changed its EMPTY situation
         bool bUpdateRequired = false;
         for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
@@ -447,19 +383,27 @@
         if (bUpdateRequired)
             updateActiveStates();
 
-        // mark that we now start capturing and distributing input
-        internalState_ |= Ticking;
-
-        // Capture all the input and handle it
+        // Capture all the input and collect the function calls
+        // No event gets triggered here yet!
         BOOST_FOREACH(InputDevice* device, devices_)
             if (device != NULL)
                 device->update(time);
 
-        // Update the states
+        // Collect functions calls for the update
         for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
             activeStatesTicked_[i]->update(time.getDeltaTime());
 
-        internalState_ &= ~Ticking;
+        // Execute all cached function calls in order
+        // Why so complicated? The problem is that an InputHandler could trigger
+        // a reload that would destroy the OIS devices or it could even leave and
+        // then destroy its own InputState. That would of course lead to access
+        // violations.
+        // If we delay the calls, then OIS and and the InputStates are not anymore
+        // in the call stack and can therefore be edited.
+        for (size_t i = 0; i < this->callBuffer_.size(); ++i)
+            this->callBuffer_[i]();
+
+        this->callBuffer_.clear();
     }
 
     /**
@@ -469,7 +413,6 @@
     */
     void InputManager::updateActiveStates()
     {
-        assert((internalState_ & InputManager::Ticking) == 0);
         // temporary resize
         for (unsigned int i = 0; i < devices_.size(); ++i)
         {
@@ -621,25 +564,30 @@
     {
         // get pointer from the map with all stored handlers
         std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
-        if (it != statesByName_.end())
+        if (it != statesByName_.end() && activeStates_.find(it->second->getPriority()) == activeStates_.end())
         {
-            // exists
-            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
+            // exists and not active
+            if (it->second->getPriority() == 0)
             {
-                // not active
-                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
+                // Get smallest possible priority between 1 and maxStateStackSize_s
+                for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
+                    rit != activeStates_.rend(); ++rit)
                 {
-                    // not scheduled for destruction
-                    // prevents a state from being added multiple times
-                    stateEnterRequests_.insert(it->second);
-                    return true;
+                    if (rit->first < InputStatePriority::HighPriority)
+                    {
+                        it->second->setPriority(rit->first + 1);
+                        break;
+                    }
                 }
+                // In case no normal handler was on the stack
+                if (it->second->getPriority() == 0)
+                    it->second->setPriority(1);
             }
-            else if (this->stateLeaveRequests_.find(it->second) != this->stateLeaveRequests_.end())
-            {
-                // State already scheduled for leaving --> cancel
-                this->stateLeaveRequests_.erase(this->stateLeaveRequests_.find(it->second));
-            }
+            activeStates_[it->second->getPriority()] = it->second;
+            updateActiveStates();
+            it->second->entered();
+
+            return true;
         }
         return false;
     }
@@ -653,20 +601,18 @@
         }
         // get pointer from the map with all stored handlers
         std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
-        if (it != statesByName_.end())
+        if (it != statesByName_.end() && activeStates_.find(it->second->getPriority()) != activeStates_.end())
         {
-            // exists
-            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
-            {
-                // active
-                stateLeaveRequests_.insert(it->second);
-                return true;
-            }
-            else if (this->stateEnterRequests_.find(it->second) != this->stateEnterRequests_.end())
-            {
-                // State already scheduled for entering --> cancel
-                this->stateEnterRequests_.erase(this->stateEnterRequests_.find(it->second));
-            }
+            // exists and active
+
+            it->second->left();
+
+            activeStates_.erase(it->second->getPriority());
+            if (it->second->getPriority() < InputStatePriority::HighPriority)
+                it->second->setPriority(0);
+            updateActiveStates();
+
+            return true;
         }
         return false;
     }
@@ -681,19 +627,8 @@
         std::map<std::string, InputState*>::iterator it = statesByName_.find(name);
         if (it != statesByName_.end())
         {
-            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
-            {
-                // The state is still active. We have to postpone
-                stateLeaveRequests_.insert(it->second);
-                stateDestroyRequests_.insert(it->second);
-            }
-            else if (this->internalState_ & Ticking)
-            {
-                // cannot remove state while ticking
-                stateDestroyRequests_.insert(it->second);
-            }
-            else
-                destroyStateInternal(it->second);
+            this->leaveState(name);
+            destroyStateInternal(it->second);
 
             return true;
         }
@@ -703,13 +638,7 @@
     //! Destroys an InputState internally.
     void InputManager::destroyStateInternal(InputState* state)
     {
-        assert(state && !(this->internalState_ & Ticking));
-        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
-        if (it != this->activeStates_.end())
-        {
-            this->activeStates_.erase(it);
-            updateActiveStates();
-        }
+        assert(state && this->activeStates_.find(state->getPriority()) == this->activeStates_.end());
         statesByName_.erase(state->getName());
         state->destroy();
     }

Modified: code/branches/gamestates2/src/libraries/core/input/InputManager.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputManager.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputManager.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -35,11 +35,11 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <boost/function.hpp>
 
 #include "util/Singleton.h"
 #include "util/TriBool.h"
 #include "core/WindowEventListener.h"
-#include "InputState.h"
 
 // tolua_begin
 namespace orxonox
@@ -75,9 +75,7 @@
         {
             Nothing       = 0x00,
             Bad           = 0x02,
-            Ticking       = 0x04,
-            Calibrating   = 0x08,
-            ReloadRequest = 0x10,
+            Calibrating   = 0x04,
         };
 
         /**
@@ -169,8 +167,17 @@
             { return devices_.size() - InputDeviceEnumerator::FirstJoyStick; }
         //! Returns a pointer to the OIS InputManager. Only you if you know what you're doing!
         OIS::InputManager* getOISInputManager() { return this->oisInputManager_; }
+        //! Returns the position of the cursor as std::pair of ints
         std::pair<int, int> getMousePosition() const;
+        //! Tells whether the mouse is used exclusively to the game
+        bool isMouseExclusive() const { return this->exclusiveMouse_; } // tolua_export
 
+        //-------------------------------
+        // Function call caching
+        //-------------------------------
+        void pushCall(const boost::function<void ()>& function)
+            { this->callBuffer_.push_back(function); }
+
         static InputManager& getInstance() { return Singleton<InputManager>::getInstance(); } // tolua_export
 
     private: // functions
@@ -207,9 +214,7 @@
         std::map<int, InputState*>          activeStates_;         //!< Contains all active input states by priority (std::map is sorted!)
         std::vector<InputState*>            activeStatesTicked_;   //!< Like activeStates_, but only contains the ones that currently receive events
 
-        std::set<InputState*>               stateEnterRequests_;   //!< Requests to enter a new state
-        std::set<InputState*>               stateLeaveRequests_;   //!< Requests to leave a running state
-        std::set<InputState*>               stateDestroyRequests_; //!< Requests to destroy a state
+        std::vector<boost::function<void ()> > callBuffer_;        //!< Caches all calls from InputStates to be executed afterwards (see preUpdate)
 
         static InputManager*                singletonPtr_s;        //!< Pointer reference to the singleton
     }; // tolua_export

Modified: code/branches/gamestates2/src/libraries/core/input/InputPrereqs.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputPrereqs.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputPrereqs.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -41,6 +41,7 @@
 #include <ois/OISKeyboard.h>
 #include <ois/OISMouse.h>
 #include <ois/OISJoyStick.h>
+#include "util/OrxEnum.h"
 
 namespace orxonox
 {
@@ -447,6 +448,20 @@
             FirstJoyStick = 2
         };
     }
+
+    //! Enumeration wrapper for input state priorities
+    struct InputStatePriority : OrxEnum<InputStatePriority>
+    {
+        OrxEnumConstructors(InputStatePriority);
+
+        static const int Empty        = -1;
+        static const int Dynamic      = 0;
+
+        static const int HighPriority = 1000;
+        static const int Console      = HighPriority + 0;
+        static const int Calibrator   = HighPriority + 1;
+        static const int Detector     = HighPriority + 2;
+    };
 }
 
 #endif /* _InputPrereqs_H__ */

Modified: code/branches/gamestates2/src/libraries/core/input/InputState.h
===================================================================
--- code/branches/gamestates2/src/libraries/core/input/InputState.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/core/input/InputState.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -34,29 +34,19 @@
 #include <cassert>
 #include <string>
 #include <vector>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
 
-#include "util/OrxEnum.h"
 #include "util/TriBool.h"
 #include "InputHandler.h"
+#include "InputManager.h"
 #include "JoyStickQuantityListener.h"
 
+#define INPUT_STATE_PUSH_CALL(deviceIndex, functionName, ...) \
+    InputManager::getInstance().pushCall(boost::function<void ()>(boost::bind(&InputHandler::functionName, handlers_[deviceIndex], __VA_ARGS__)))
+
 namespace orxonox
 {
-    //! Enumeration wrapper for input state priorities
-    struct InputStatePriority : OrxEnum<InputStatePriority>
-    {
-        OrxEnumConstructors(InputStatePriority);
-
-        static const int Empty        = -1;
-        static const int Dynamic      = 0;
-
-        static const int HighPriority = 1000;
-        static const int Console      = HighPriority + 0;
-        static const int Calibrator   = HighPriority + 1;
-        static const int Detector     = HighPriority + 2;
-    };
-
-
     /**
     @brief
         InputStates allow you to customise the input event targets at runtime.
@@ -143,8 +133,8 @@
         void update(float dt);
 
         //! Generic function that distributes all 9 button events
-        template <typename EventType, class Traits>
-        void buttonEvent(unsigned int device, const typename Traits::ButtonTypeParam button);
+        template <typename EventType, class ButtonTypeParam>
+        void buttonEvent(unsigned int device, ButtonTypeParam button);
 
         //! Event handler
         void mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize);
@@ -189,7 +179,7 @@
     {
         for (unsigned int i = 0; i < handlers_.size(); ++i)
             if (handlers_[i] != NULL)
-                handlers_[i]->allDevicesUpdated(dt);
+                INPUT_STATE_PUSH_CALL(i, allDevicesUpdated, dt);
     }
 
     FORCEINLINE void InputState::update(float dt, unsigned int device)
@@ -198,46 +188,50 @@
         {
         case InputDeviceEnumerator::Keyboard:
             if (handlers_[keyboardIndex_s] != NULL)
-                handlers_[keyboardIndex_s]->keyboardUpdated(dt);
+                INPUT_STATE_PUSH_CALL(keyboardIndex_s, keyboardUpdated, dt);
             break;
 
         case InputDeviceEnumerator::Mouse:
             if (handlers_[mouseIndex_s] != NULL)
-                handlers_[mouseIndex_s]->mouseUpdated(dt);
+                INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseUpdated, dt);
             break;
 
         default: // joy sticks
             if (handlers_[device] != NULL)
-                handlers_[device]->joyStickUpdated(device - firstJoyStickIndex_s, dt);
+                INPUT_STATE_PUSH_CALL(device, joyStickUpdated, device - firstJoyStickIndex_s, dt);
             break;
         }
     }
 
-    template <typename EventType, class Traits>
-    FORCEINLINE void InputState::buttonEvent(unsigned int device, const typename Traits::ButtonTypeParam button)
+    template <typename EventType, class ButtonTypeParam>
+    FORCEINLINE void InputState::buttonEvent(unsigned int device, typename ButtonTypeParam button)
     {
         assert(device < handlers_.size());
         if (handlers_[device] != NULL)
-            handlers_[device]->buttonEvent(device, button, EventType());
+        {
+            // We have to store the function pointer to tell the compiler about its actual type because of overloading
+            void (InputHandler::*function)(unsigned int, ButtonTypeParam, EventType) = &InputHandler::buttonEvent<ButtonTypeParam>;
+            InputManager::getInstance().pushCall(boost::function<void ()>(boost::bind(function, handlers_[device], device, button, EventType())));
+        }
     }
 
     FORCEINLINE void InputState::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
     {
         if (handlers_[mouseIndex_s] != NULL)
-            handlers_[mouseIndex_s]->mouseMoved(abs, rel, clippingSize);
+            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseMoved, abs, rel, clippingSize);
     }
 
     FORCEINLINE void InputState::mouseScrolled(int abs, int rel)
     {
         if (handlers_[mouseIndex_s] != NULL)
-            handlers_[mouseIndex_s]->mouseScrolled(abs, rel);
+            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseScrolled, abs, rel);
     }
 
     FORCEINLINE void InputState::joyStickAxisMoved(unsigned int device, unsigned int axis, float value)
     {
         assert(device < handlers_.size());
         if (handlers_[device] != NULL)
-            handlers_[device]->axisMoved(device - firstJoyStickIndex_s, axis, value);
+            INPUT_STATE_PUSH_CALL(device, axisMoved, device - firstJoyStickIndex_s, axis, value);
     }
 }
 

Modified: code/branches/gamestates2/src/libraries/util/Singleton.h
===================================================================
--- code/branches/gamestates2/src/libraries/util/Singleton.h	2010-03-30 22:54:35 UTC (rev 6661)
+++ code/branches/gamestates2/src/libraries/util/Singleton.h	2010-03-30 23:05:28 UTC (rev 6662)
@@ -48,26 +48,26 @@
     {
     public:
         //! Returns a reference to the singleton instance
-        static T& getInstance()
+        FORCEINLINE static T& getInstance()
         {
             assert(T::singletonPtr_s != NULL);
             return *T::singletonPtr_s;
         }
 
         //! Tells whether the singleton has been created
-        static bool exists()
+        FORCEINLINE static bool exists()
         {
             return (T::singletonPtr_s != NULL);
         }
 
         //! Update method called by ClassSingletonManager (if used)
-        void preUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->preUpdate(time); }
+        FORCEINLINE void preUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->preUpdate(time); }
         //! Empty update method for the static polymorphism
-        void preUpdate(const Clock& time) { }
+        FORCEINLINE void preUpdate(const Clock& time) { }
         //! Update method called by ClassSingletonManager (if used)
-        void postUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->postUpdate(time); }
+        FORCEINLINE void postUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->postUpdate(time); }
         //! Empty update method for the static polymorphism
-        void postUpdate(const Clock& time) { }
+        FORCEINLINE void postUpdate(const Clock& time) { }
 
     protected:
         //! Constructor sets the singleton instance pointer




More information about the Orxonox-commit mailing list